save checkpoint: save features

This commit is contained in:
master
2026-02-12 10:27:23 +02:00
parent dca86e1248
commit 5bca406787
8837 changed files with 1796879 additions and 5294 deletions

View File

@@ -41,6 +41,18 @@ Before selecting any feature, run this checklist in order:
4. Record the selected feature transition in state notes before running Tier 0.
5. Create a fresh run directory (`run-XYZ`) before collecting any tier artifacts.
### 0.1 Multi-Agent Collision Handling (Mandatory)
When multiple agents work in parallel, the problems-first lock still applies.
1. Always claim the selected problem feature first in its state notes (who, when, run-id).
2. If another agent is actively writing the same feature and continuing would create conflicting writes, mark the current task as blocked/obstacle in sprint notes immediately.
3. Transition the feature to a terminal auditable state before moving on:
- Prefer `skipped` with `skipReason = "owned_by_other_agent"` when another agent has clearly taken ownership and is progressing.
- Use `blocked` only when ownership is unclear or no reliable owner progress evidence exists.
4. After recording the obstacle and reason, continue with the next highest-priority problem feature.
5. Never start a new `queued` feature while any non-terminal problem feature remains.
---
## 1. Directory Layout
@@ -119,6 +131,7 @@ Features may ONLY be marked `skipped` if they match one of these 3 physical cons
- `hardware_required`: Requires physical HSM, smart card, or eIDAS hardware token
- `multi_datacenter`: Requires geographically distributed infrastructure
- `air_gap_network`: Requires a physically disconnected network
- `owned_by_other_agent`: Active parallel ownership conflict with auditable evidence in state/sprint notes
**Everything else MUST be tested.** Features that were previously classified as
"performance benchmarking" or "multi-node cluster" should be tested with whatever

View File

@@ -0,0 +1,6 @@
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43ed130493de postgres:18.1-alpine "docker-entrypoint.s…" 40 minutes ago Up 40 minutes (healthy) 127.1.1.1:5432->5432/tcp stellaops-dev-postgres
aebfe19eb9df ghcr.io/sigstore/rekor-tiles:latest "rekor-server serve" 40 minutes ago Restarting (1) 49 seconds ago stellaops-dev-rekor
f0d9958bcbcc chrislusf/seaweedfs:latest "/entrypoint.sh serv…" 40 minutes ago Up 8 seconds (health: starting) 127.1.1.3:8080->8080/tcp stellaops-dev-rustfs
9936bf08d62f valkey/valkey:9.0.1-alpine "docker-entrypoint.s…" 40 minutes ago Up 40 minutes (healthy) 127.1.1.2:6379->6379/tcp stellaops-dev-valkey
0719ba74ad84 ghcr.io/project-zot/zot-linux-amd64:v2.1.3 "/usr/local/bin/zot-…" 40 minutes ago Up 40 minutes (unhealthy) 127.1.1.5:80->5000/tcp stellaops-dev-registry

View File

@@ -0,0 +1 @@
Docker version 29.1.5, build 0e6fee6

View File

@@ -0,0 +1 @@
10.0.200-preview.0.26103.119

View File

@@ -0,0 +1,79 @@
{
"type": "source",
"module": "advisoryai",
"feature": "ai-action-policy-gate",
"runId": "run-002",
"capturedAtUtc": "2026-02-11T11:53:22.0969824Z",
"filesChecked": [
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionPolicyGate.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionRegistry.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionExecutor.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionAuditLedger.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ApprovalWorkflowAdapter.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/IdempotencyHandler.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionDefinition.cs",
"src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/Actions/ActionWorkflowIntegrationTests.cs"
],
"found": [
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionPolicyGate.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionRegistry.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionExecutor.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionAuditLedger.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ApprovalWorkflowAdapter.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/IdempotencyHandler.cs",
"src/AdvisoryAI/StellaOps.AdvisoryAI/Actions/ActionDefinition.cs",
"src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/Actions/ActionWorkflowIntegrationTests.cs"
],
"missing": [
],
"declarationChecks": [
{
"pattern": "class ActionPolicyGate",
"found": true,
"sample": "src/AdvisoryAI\\__Tests\\StellaOps.AdvisoryAI.Tests\\Actions\\ActionPolicyGateTests.cs:19:public sealed class ActionPolicyGateTests\nsrc/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ActionPolicyGate.cs:16:internal sealed class ActionPolicyGate : IActionPolicyGate"
},
{
"pattern": "class ActionRegistry",
"found": true,
"sample": "src/AdvisoryAI\\__Tests\\StellaOps.AdvisoryAI.Tests\\Actions\\ActionRegistryTests.cs:17:public sealed class ActionRegistryTests\nsrc/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ActionRegistry.cs:15:internal sealed partial class ActionRegistry : IActionRegistry"
},
{
"pattern": "class ActionExecutor",
"found": true,
"sample": "src/AdvisoryAI\\__Tests\\StellaOps.AdvisoryAI.Tests\\Actions\\ActionExecutorTests.cs:20:public sealed class ActionExecutorTests\nsrc/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ActionExecutor.cs:16:internal sealed class ActionExecutor : IActionExecutor"
},
{
"pattern": "class ActionAuditLedger",
"found": true,
"sample": "src/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ActionAuditLedger.cs:18:internal sealed class ActionAuditLedger : IActionAuditLedger"
},
{
"pattern": "class ApprovalWorkflowAdapter",
"found": true,
"sample": "src/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ApprovalWorkflowAdapter.cs:17:internal sealed class ApprovalWorkflowAdapter : IApprovalWorkflowAdapter"
},
{
"pattern": "class IdempotencyHandler",
"found": true,
"sample": "src/AdvisoryAI\\__Tests\\StellaOps.AdvisoryAI.Tests\\Actions\\IdempotencyHandlerTests.cs:19:public sealed class IdempotencyHandlerTests\nsrc/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\IdempotencyHandler.cs:20:internal sealed class IdempotencyHandler : IIdempotencyHandler"
},
{
"pattern": "record ActionDefinition",
"found": true,
"sample": "src/AdvisoryAI\\StellaOps.AdvisoryAI\\Chat\\ActionProposalParser.cs:211:internal sealed record ActionDefinition\nsrc/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ActionDefinition.cs:13:public sealed record ActionDefinition"
},
{
"pattern": "class ActionWorkflowIntegrationTests",
"found": true,
"sample": "src/AdvisoryAI\\__Tests\\StellaOps.AdvisoryAI.Tests\\Actions\\ActionWorkflowIntegrationTests.cs:20:public sealed class ActionWorkflowIntegrationTests"
},
{
"pattern": "AwaitApprovalCompletion",
"found": true,
"sample": "src/AdvisoryAI\\__Tests\\StellaOps.AdvisoryAI.Tests\\Actions\\ActionWorkflowIntegrationTests.cs:192: AwaitApprovalCompletion = awaitApprovalCompletion,\nsrc/AdvisoryAI\\StellaOps.AdvisoryAI\\Actions\\ActionExecutor.cs:275: if (!_options.AwaitApprovalCompletion)"
}
],
"missingRatio": 0,
"verdict": "pass"
}

View File

@@ -0,0 +1,47 @@
{
"type": "build_test",
"module": "advisoryai",
"feature": "ai-action-policy-gate",
"runId": "run-002",
"capturedAtUtc": "2026-02-11T11:57:17.2947772Z",
"commands": [
{
"name": "build-core",
"command": "dotnet build src/AdvisoryAI/StellaOps.AdvisoryAI/StellaOps.AdvisoryAI.csproj -c Release --nologo -v minimal",
"exitCode": 0,
"log": "docs\\qa\\feature-checks\\runs\\advisoryai\\ai-action-policy-gate\\run-002\\evidence\\tier1-build-core.txt",
"result": "pass"
},
{
"name": "build-hosting",
"command": "dotnet build src/AdvisoryAI/StellaOps.AdvisoryAI.Hosting/StellaOps.AdvisoryAI.Hosting.csproj -c Release --nologo -v minimal",
"exitCode": 0,
"log": "docs\\qa\\feature-checks\\runs\\advisoryai\\ai-action-policy-gate\\run-002\\evidence\\tier1-build-hosting.txt",
"result": "pass"
},
{
"name": "build-web",
"command": "dotnet build src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/StellaOps.AdvisoryAI.WebService.csproj -c Release --nologo -v minimal",
"exitCode": 0,
"log": "docs\\qa\\feature-checks\\runs\\advisoryai\\ai-action-policy-gate\\run-002\\evidence\\tier1-build-web.txt",
"result": "pass"
},
{
"name": "build-tests",
"command": "dotnet build src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj -c Release --nologo -v minimal",
"exitCode": 0,
"log": "docs\\qa\\feature-checks\\runs\\advisoryai\\ai-action-policy-gate\\run-002\\evidence\\tier1-build-tests.txt",
"result": "pass"
},
{
"name": "test-suite",
"command": "dotnet test src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj -c Release --nologo -v minimal",
"exitCode": 0,
"log": "docs\\qa\\feature-checks\\runs\\advisoryai\\ai-action-policy-gate\\run-002\\evidence\\tier1-test-suite.txt",
"result": "pass"
}
],
"buildResult": "pass",
"testResult": "pass",
"verdict": "pass"
}

View File

@@ -0,0 +1,18 @@
{
"type": "integration",
"module": "advisoryai",
"feature": "ai-action-policy-gate",
"runId": "run-002",
"capturedAtUtc": "2026-02-11T11:55:03.0629583Z",
"command": "src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/bin/Release/net10.0/StellaOps.AdvisoryAI.Tests.exe -class StellaOps.AdvisoryAI.Tests.Actions.ActionWorkflowIntegrationTests -reporter verbose",
"exitCode": 0,
"behaviorVerified": [
"Action requiring approval transitions through ApprovalRequested/Approved/Executed audit outcomes when await-approval mode is enabled.",
"Repeated execution of the same approved action returns idempotent prior result and records IdempotentSkipped audit outcome.",
"Policy denial for insufficient role blocks action execution and records DeniedByPolicy audit outcome."
],
"logs": [
"evidence/tier2-action-workflow-integration.txt"
],
"verdict": "pass"
}

View File

@@ -0,0 +1,14 @@
path exists
---- ------
src/AirGap/__Libraries/StellaOps.AirGap.Bundle/ True
src/AirGap/__Libraries/StellaOps.AirGap.Persistence/ True
src/AirGap/__Libraries/StellaOps.AirGap.Sync/ True
src/AirGap/__Tests/ True
src/AirGap/StellaOps.AirGap.Controller/ True
src/AirGap/StellaOps.AirGap.Importer/ True
src/AirGap/StellaOps.AirGap.Policy/ True
src/AirGap/StellaOps.AirGap.Storage.Postgres/ True

View File

@@ -0,0 +1,67 @@
[
{
"declaration": "class AirGapStateService",
"found": true,
"hitCount": 2,
"sample": [
"src/AirGap\\StellaOps.AirGap.Controller\\Services\\AirGapStateService.cs:8:public sealed class AirGapStateService",
"src/AirGap\\__Tests\\StellaOps.AirGap.Controller.Tests\\AirGapStateServiceTests.cs:11:public class AirGapStateServiceTests"
]
},
{
"declaration": "record AirGapState",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Domain\\AirGapState.cs:5:public sealed record AirGapState"
},
{
"declaration": "class AirGapEndpoints",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Endpoints\\AirGapEndpoints.cs:12:internal static class AirGapEndpoints"
},
{
"declaration": "class BundleImportPlanner",
"found": true,
"hitCount": 2,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Planning\\BundleImportPlanner.cs:9:public sealed class BundleImportPlanner",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\BundleImportPlannerTests.cs:7:public class BundleImportPlannerTests"
]
},
{
"declaration": "class FileSystemQuarantineService",
"found": true,
"hitCount": 2,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Quarantine\\FileSystemQuarantineService.cs:12:public sealed class FileSystemQuarantineService : IQuarantineService",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\Quarantine\\FileSystemQuarantineServiceTests.cs:9:public sealed class FileSystemQuarantineServiceTests"
]
},
{
"declaration": "interface IQuarantineService",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Importer\\Quarantine\\IQuarantineService.cs:3:public interface IQuarantineService"
},
{
"declaration": "class EvidenceReconciler",
"found": true,
"hitCount": 3,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\EvidenceReconciler.cs:72:public sealed class EvidenceReconciler : IEvidenceReconciler",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\Reconciliation\\EvidenceReconcilerDsseSigningTests.cs:8:public sealed class EvidenceReconcilerDsseSigningTests",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\Reconciliation\\EvidenceReconcilerVexTests.cs:9:public sealed class EvidenceReconcilerVexTests"
]
},
{
"declaration": "class EvidenceGraph",
"found": true,
"hitCount": 3,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\EvidenceGraph.cs:19:public sealed class EvidenceGraph",
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\EvidenceGraph.cs:211:public sealed class EvidenceGraphSerializer",
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\Signing\\EvidenceGraphDsseSigner.cs:17:internal sealed class EvidenceGraphDsseSigner"
]
}
]

View File

@@ -0,0 +1,2 @@
Tier0PathCheck: filesChecked=8 missing=0 missingPct=0
Tier0DeclarationCheck: declarationsChecked=8 allFound=True

View File

@@ -0,0 +1,4 @@
buildExitCode=0
importerTestsExitCode=0
controllerTestsExitCode=0
bundleTestsExitCode=0

View File

@@ -0,0 +1,2 @@
importerClassExitCode=0
controllerClassExitCode=0

View File

@@ -0,0 +1,95 @@
{
"capturedAtUtc": "2026-02-11T13:48:09.3683617Z",
"featureFile": "docs/features/unchecked/airgap/air-gap-bundle-system.md",
"filesChecked": [
"src/AirGap/__Libraries/StellaOps.AirGap.Bundle/",
"src/AirGap/__Libraries/StellaOps.AirGap.Persistence/",
"src/AirGap/__Libraries/StellaOps.AirGap.Sync/",
"src/AirGap/__Tests/",
"src/AirGap/StellaOps.AirGap.Controller/",
"src/AirGap/StellaOps.AirGap.Importer/",
"src/AirGap/StellaOps.AirGap.Policy/",
"src/AirGap/StellaOps.AirGap.Storage.Postgres/"
],
"found": [
"src/AirGap/__Libraries/StellaOps.AirGap.Bundle/",
"src/AirGap/__Libraries/StellaOps.AirGap.Persistence/",
"src/AirGap/__Libraries/StellaOps.AirGap.Sync/",
"src/AirGap/__Tests/",
"src/AirGap/StellaOps.AirGap.Controller/",
"src/AirGap/StellaOps.AirGap.Importer/",
"src/AirGap/StellaOps.AirGap.Policy/",
"src/AirGap/StellaOps.AirGap.Storage.Postgres/"
],
"missing": [
],
"declarationChecks": [
{
"declaration": "class AirGapStateService",
"found": true,
"hitCount": 2,
"sample": [
"src/AirGap\\StellaOps.AirGap.Controller\\Services\\AirGapStateService.cs:8:public sealed class AirGapStateService",
"src/AirGap\\__Tests\\StellaOps.AirGap.Controller.Tests\\AirGapStateServiceTests.cs:11:public class AirGapStateServiceTests"
]
},
{
"declaration": "record AirGapState",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Domain\\AirGapState.cs:5:public sealed record AirGapState"
},
{
"declaration": "class AirGapEndpoints",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Endpoints\\AirGapEndpoints.cs:12:internal static class AirGapEndpoints"
},
{
"declaration": "class BundleImportPlanner",
"found": true,
"hitCount": 2,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Planning\\BundleImportPlanner.cs:9:public sealed class BundleImportPlanner",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\BundleImportPlannerTests.cs:7:public class BundleImportPlannerTests"
]
},
{
"declaration": "class FileSystemQuarantineService",
"found": true,
"hitCount": 2,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Quarantine\\FileSystemQuarantineService.cs:12:public sealed class FileSystemQuarantineService : IQuarantineService",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\Quarantine\\FileSystemQuarantineServiceTests.cs:9:public sealed class FileSystemQuarantineServiceTests"
]
},
{
"declaration": "interface IQuarantineService",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Importer\\Quarantine\\IQuarantineService.cs:3:public interface IQuarantineService"
},
{
"declaration": "class EvidenceReconciler",
"found": true,
"hitCount": 3,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\EvidenceReconciler.cs:72:public sealed class EvidenceReconciler : IEvidenceReconciler",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\Reconciliation\\EvidenceReconcilerDsseSigningTests.cs:8:public sealed class EvidenceReconcilerDsseSigningTests",
"src/AirGap\\__Tests\\StellaOps.AirGap.Importer.Tests\\Reconciliation\\EvidenceReconcilerVexTests.cs:9:public sealed class EvidenceReconcilerVexTests"
]
},
{
"declaration": "class EvidenceGraph",
"found": true,
"hitCount": 3,
"sample": [
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\EvidenceGraph.cs:19:public sealed class EvidenceGraph",
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\EvidenceGraph.cs:211:public sealed class EvidenceGraphSerializer",
"src/AirGap\\StellaOps.AirGap.Importer\\Reconciliation\\Signing\\EvidenceGraphDsseSigner.cs:17:internal sealed class EvidenceGraphDsseSigner"
]
}
],
"verdict": "pass"
}

View File

@@ -0,0 +1,70 @@
{
"capturedAtUtc": "2026-02-11T13:54:05.1094812Z",
"projects": [
"src/AirGap/StellaOps.AirGap.Controller/StellaOps.AirGap.Controller.csproj",
"src/AirGap/StellaOps.AirGap.Importer/StellaOps.AirGap.Importer.csproj",
"src/AirGap/__Libraries/StellaOps.AirGap.Bundle/StellaOps.AirGap.Bundle.csproj",
"src/AirGap/__Tests/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj",
"src/AirGap/__Tests/StellaOps.AirGap.Controller.Tests/StellaOps.AirGap.Controller.Tests.csproj"
],
"buildResult": "pass",
"testResult": "pass",
"commands": [
{
"command": "dotnet build src/AirGap/StellaOps.AirGap.Controller/StellaOps.AirGap.Controller.csproj",
"exitCode": 0,
"evidence": "evidence/02-tier1-build-controller.txt"
},
{
"command": "dotnet build src/AirGap/StellaOps.AirGap.Importer/StellaOps.AirGap.Importer.csproj",
"exitCode": 0,
"evidence": "evidence/02a-tier1-build-importer.txt"
},
{
"command": "dotnet build src/AirGap/__Libraries/StellaOps.AirGap.Bundle/StellaOps.AirGap.Bundle.csproj",
"exitCode": 0,
"evidence": "evidence/02b-tier1-build-bundle-lib.txt"
},
{
"command": "dotnet build src/AirGap/__Tests/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj",
"exitCode": 0,
"evidence": "evidence/02c-tier1-build-importer-tests.txt"
},
{
"command": "dotnet build src/AirGap/__Tests/StellaOps.AirGap.Controller.Tests/StellaOps.AirGap.Controller.Tests.csproj",
"exitCode": 0,
"evidence": "evidence/02d-tier1-build-controller-tests.txt"
},
{
"command": "dotnet test src/AirGap/__Tests/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj",
"exitCode": 0,
"testsPassed": 151,
"testsFailed": 0,
"evidence": "evidence/03-tier1-test-importer-suite.txt"
},
{
"command": "dotnet test src/AirGap/__Tests/StellaOps.AirGap.Controller.Tests/StellaOps.AirGap.Controller.Tests.csproj",
"exitCode": 0,
"testsPassed": 27,
"testsFailed": 0,
"evidence": "evidence/03a-tier1-test-controller-suite.txt"
},
{
"command": "dotnet test src/AirGap/__Libraries/__Tests/StellaOps.AirGap.Bundle.Tests/StellaOps.AirGap.Bundle.Tests.csproj",
"exitCode": 0,
"testsPassed": 150,
"testsFailed": 0,
"evidence": "evidence/03b-tier1-test-bundle-library.txt"
},
{
"command": "dotnet test src/AirGap/__Tests/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj --filter \"FullyQualifiedName~BundleImportPlannerTests|FullyQualifiedName~FileSystemQuarantineServiceTests|FullyQualifiedName~VersionMonotonicityCheckerTests|FullyQualifiedName~ImportValidatorIntegrationTests|FullyQualifiedName~EvidenceReconciler\"",
"exitCode": 0,
"testsPassed": 13,
"testsFailed": 0,
"evidence": "evidence/03b-tier1-test-feature-classes-importer.txt"
}
],
"errors": [
]
}

View File

@@ -0,0 +1,16 @@
{
"type": "integration",
"capturedAtUtc": "2026-02-11T13:54:05.1094812Z",
"testFilter": "FullyQualifiedName~StellaOps.AirGap.Controller.Tests.AirGapEndpointTests|FullyQualifiedName~StellaOps.AirGap.Controller.Tests.AirGapStateServiceTests",
"command": "dotnet test src/AirGap/__Tests/StellaOps.AirGap.Controller.Tests/StellaOps.AirGap.Controller.Tests.csproj --filter \"FullyQualifiedName~StellaOps.AirGap.Controller.Tests.AirGapEndpointTests|FullyQualifiedName~StellaOps.AirGap.Controller.Tests.AirGapStateServiceTests\"",
"commandExitCode": 0,
"testsRun": 12,
"testsPassed": 12,
"testsFailed": 0,
"behaviorVerified": [
"Controller endpoint behavior for /system/airgap/seal, /system/airgap/status, and /system/airgap/verify including validation and authorization failures",
"Air-gap state service transition semantics (seal/unseal), per-content staleness budgets, and drift baseline persistence"
],
"evidenceLog": "evidence/04-tier2-test-feature-classes-controller.txt",
"verdict": "pass"
}

View File

@@ -0,0 +1,16 @@
Feature: air-gap-epistemic-mode-with-sealed-startup-and-feed-snapshots
Run: run-001
File checks:
- src/AirGap/StellaOps.AirGap.Controller/Services/AirGapStartupDiagnosticsHostedService.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Controller/Options/AirGapStartupOptions.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Controller/Domain/AirGapState.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Controller/Services/AirGapStateService.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Controller/Stores/IAirGapStateStore.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Controller/Stores/InMemoryAirGapStateStore.cs :: FOUND
- src/AirGap/__Libraries/StellaOps.AirGap.Bundle/Services/SnapshotBundleWriter.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Importer/Policy/OfflineVerificationPolicy.cs :: FOUND
- src/AirGap/StellaOps.AirGap.Importer/Policy/OfflineVerificationPolicyLoader.cs :: FOUND
Summary: checked=9 found=9 missing=0 missingPct=0
Declaration parity: checked=9 allFound=True

View File

@@ -0,0 +1,60 @@
[
{
"declaration": "class AirGapStartupDiagnosticsHostedService",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Services\\AirGapStartupDiagnosticsHostedService.cs:12:internal sealed class AirGapStartupDiagnosticsHostedService : IHostedService"
},
{
"declaration": "class AirGapStartupOptions",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Options\\AirGapStartupOptions.cs:3:public sealed class AirGapStartupOptions"
},
{
"declaration": "record AirGapState",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Domain\\AirGapState.cs:5:public sealed record AirGapState"
},
{
"declaration": "class AirGapStateService",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Services\\AirGapStateService.cs:8:public sealed class AirGapStateService"
},
{
"declaration": "interface IAirGapStateStore",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Stores\\IAirGapStateStore.cs:5:public interface IAirGapStateStore"
},
{
"declaration": "class InMemoryAirGapStateStore",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Controller\\Stores\\InMemoryAirGapStateStore.cs:7:public sealed class InMemoryAirGapStateStore : IAirGapStateStore"
},
{
"declaration": "class SnapshotBundleWriter",
"found": true,
"hitCount": 17,
"sample": [
"src/AirGap\\__Libraries\\StellaOps.AirGap.Bundle\\Services\\SnapshotBundleWriter.Sections.Advisories.cs:5:public sealed partial class SnapshotBundleWriter",
"src/AirGap\\__Libraries\\StellaOps.AirGap.Bundle\\Services\\SnapshotBundleWriter.Manifest.cs:7:public sealed partial class SnapshotBundleWriter",
"src/AirGap\\__Libraries\\StellaOps.AirGap.Bundle\\Services\\SnapshotBundleWriter.Sections.TimeAnchor.cs:6:public sealed partial class SnapshotBundleWriter"
]
},
{
"declaration": "record OfflineVerificationPolicy",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Importer\\Policy\\OfflineVerificationPolicy.cs:5:public sealed record OfflineVerificationPolicy"
},
{
"declaration": "class OfflineVerificationPolicyLoader",
"found": true,
"hitCount": 1,
"sample": "src/AirGap\\StellaOps.AirGap.Importer\\Policy\\OfflineVerificationPolicyLoader.cs:11:public static class OfflineVerificationPolicyLoader"
}
]

View File

@@ -0,0 +1,2 @@
Tier0PathCheck: filesChecked=9 missing=0 missingPct=0
Tier0DeclarationCheck: declarationsChecked=9 allFound=True

View File

@@ -0,0 +1,7 @@
buildControllerExitCode=0
buildImporterExitCode=0
buildBundleExitCode=0
buildImporterTestsExitCode=0
controllerTestsExitCode=0
importerPolicyTestsExitCode=0
bundleSnapshotTestsExitCode=0

View File

@@ -0,0 +1,37 @@
Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to read parameter "SealRequest request" from the request body as JSON.
---> System.Text.Json.JsonException: 'p' is an invalid start of a property name. Expected a '"'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
---> System.Text.Json.JsonReaderException: 'p' is an invalid start of a property name. Expected a '"'. LineNumber: 0 | BytePositionInLine: 1.
at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.ContinueDeserialize[TReadBufferState,TStream](TReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, T& value)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync[TReadBufferState,TStream](TStream utf8Json, TReadBufferState bufferState, CancellationToken cancellationToken)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(PipeReader utf8Json, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<HandleRequestBodyAndCompileRequestDelegateForJson>g__TryReadBodyAsync|102_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest, JsonTypeInfo jsonTypeInfo)
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Http.RequestDelegateFactory.Log.InvalidJsonRequestBody(HttpContext httpContext, String parameterTypeName, String parameterName, Exception exception, Boolean shouldThrow)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<HandleRequestBodyAndCompileRequestDelegateForJson>g__TryReadBodyAsync|102_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest, JsonTypeInfo jsonTypeInfo)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass102_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Host: 127.0.0.1:5041
User-Agent: curl/8.16.0
Content-Type: application/json
Content-Length: 75
scope: airgap:seal
x-tenant-id: tenant-a

View File

@@ -0,0 +1,37 @@
Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to read parameter "SealRequest request" from the request body as JSON.
---> System.Text.Json.JsonException: 'p' is an invalid start of a property name. Expected a '"'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
---> System.Text.Json.JsonReaderException: 'p' is an invalid start of a property name. Expected a '"'. LineNumber: 0 | BytePositionInLine: 1.
at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.ContinueDeserialize[TReadBufferState,TStream](TReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, T& value)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync[TReadBufferState,TStream](TStream utf8Json, TReadBufferState bufferState, CancellationToken cancellationToken)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(PipeReader utf8Json, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync(HttpRequest request, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<HandleRequestBodyAndCompileRequestDelegateForJson>g__TryReadBodyAsync|102_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest, JsonTypeInfo jsonTypeInfo)
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Http.RequestDelegateFactory.Log.InvalidJsonRequestBody(HttpContext httpContext, String parameterTypeName, String parameterName, Exception exception, Boolean shouldThrow)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<HandleRequestBodyAndCompileRequestDelegateForJson>g__TryReadBodyAsync|102_0(HttpContext httpContext, Type bodyType, String parameterTypeName, String parameterName, Boolean allowEmptyRequestBody, Boolean throwOnBadRequest, JsonTypeInfo jsonTypeInfo)
at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass102_2.<<HandleRequestBodyAndCompileRequestDelegateForJson>b__2>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Host: 127.0.0.1:5041
User-Agent: curl/8.16.0
Content-Type: application/json
Content-Length: 185
scope: airgap:seal airgap:status:read
x-tenant-id: tenant-ops

View File

@@ -0,0 +1 @@
{"tenantId":"tenant-ops","sealed":false,"policyHash":null,"timeAnchor":{"anchorTime":"0001-01-01T00:00:00+00:00","source":"unknown","format":"unknown","signatureFingerprint":"","tokenDigest":""},"staleness":{"ageSeconds":0,"warningSeconds":0,"breachSeconds":0,"isWarning":false,"isBreach":false,"secondsRemaining":0},"driftSeconds":0,"driftBaselineSeconds":0,"secondsRemaining":0,"contentStaleness":{},"lastTransitionAt":"0001-01-01T00:00:00+00:00","evaluatedAt":"2026-02-11T14:06:48.3262049+00:00"}

Some files were not shown because too many files have changed in this diff Show More