Skip to content

Commit ec12d5d

Browse files
committed
Add commercial evidence filesystem artifact writer
1 parent b89e375 commit ec12d5d

7 files changed

Lines changed: 198 additions & 4 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ The first production milestone is M3UA over a transport abstraction. SCCP, TCAP,
7575
| Commercial evidence execution orchestration | Phase 37 foundation-complete: evidence execution run identity, stage catalog, operator command plan, execution environment contract, artifact collection manifest, digest/redaction verification, blocker classification, retry/resume policy, status reporting, and final validation are available; real retained execution artifacts are still required before commercial publication |
7676
| Commercial evidence artifact intake | Phase 38 foundation-complete: artifact intake target identity, artifact source registration, SHA-256 digest coverage, redaction review, completeness evaluation, dossier reporting, promotion handoff, execution-to-dossier bridge, status reporting, and final validation are available, binding a stable intake id, reviewer identity, UTC receipt time, run-scoped dossier root, concrete source paths, unique retained dossier paths, retained digests, trace-bearing artifact approvals, explicit intake blockers, retained Markdown summary, digest-covered handoff, end-to-end intake assembly, and intake readiness status to a governed execution run; real artifact files are still required before commercial publication |
7777
| Commercial evidence file verification | Phase 39 foundation-complete: retained file evidence item verification, retained file manifest coverage, file verification blocker reporting, retention ledger modeling, integrity sealing, publication attachment planning, verified promotion gating, command planning, status reporting, final validation, and documentation alignment are available, checking file existence, non-empty size, SHA-256 validity, digest match, UTC observation time, unique retained paths, promotion-required handoff coverage, explicit verification blockers, reviewer identity, immutable retention, UTC retention windows, minimum duration, deterministic aggregate ledger digests, sealed ledger attachment coverage, trace-bearing redaction approval, commercial readiness report presence, explicit promotion approval, workflow-ready verification command order, and readiness status separation; real retained file evidence remains required before commercial publication |
78-
| Commercial evidence filesystem execution | Phase 40 in progress: filesystem observation, manifest execution, and verification report execution are available, reading retained files from disk, computing real SHA-256 digests, reporting file existence and size, supporting retained-path-to-local-path overrides, building retained file manifests from real observations, and exposing blocker-aware retained file reports from filesystem evidence; artifact writing, ledger execution, seal execution, attachment execution, promotion execution, command materialization, status reporting, and final validation remain |
78+
| Commercial evidence filesystem execution | Phase 40 in progress: filesystem observation, manifest execution, verification report execution, and artifact writing are available, reading retained files from disk, computing real SHA-256 digests, reporting file existence and size, supporting retained-path-to-local-path overrides, building retained file manifests from real observations, exposing blocker-aware retained file reports from filesystem evidence, and writing retained Markdown/TSV verification artifacts; ledger execution, seal execution, attachment execution, promotion execution, command materialization, status reporting, and final validation remain |
7979

8080
## Requirements
8181

docs/PHASE40_COMMERCIAL_EVIDENCE_FILESYSTEM_EXECUTION.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ This unit lets the verification pipeline evaluate a complete retained handoff us
3939

4040
This unit is the first end-to-end filesystem verification pass: observe files, build the manifest, and produce a blocker-aware report.
4141

42+
## Unit 4 - Verification Artifact Writing
43+
44+
`SigtranCommercialEvidenceFileSystemArtifactWriters` writes filesystem verification artifacts to disk:
45+
46+
- Markdown verification report.
47+
- Tab-separated observation manifest.
48+
- UTC write timestamp.
49+
- Existence and non-empty content checks for the written artifacts.
50+
51+
This unit gives release operators retained files they can attach to the commercial evidence dossier after filesystem verification succeeds.
52+
4253
## Validation
4354

4455
Each unit in this phase is validated with:

docs/PHASE40_SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ Phase 40 prepares the SDK to run commercial evidence file verification against r
77
- Filesystem observer that computes SHA-256 digests from existing retained files and maps missing files into explicit non-verified retained file observations.
88
- Filesystem manifest builder that observes every promotion handoff item, supports retained-path-to-local-path overrides, and builds a retained file manifest from real observations.
99
- Filesystem verification report execution that evaluates real observations and exposes retained file blockers such as missing files.
10+
- Verification artifact writer that retains a Markdown verification report and tab-separated observation manifest on disk.
1011

1112
## Readiness Position
1213

13-
The phase is in progress. Filesystem observation, manifest execution, and report execution are available. Artifact writing, ledger execution, seal execution, attachment execution, promotion execution, command materialization, status reporting, and final validation remain.
14+
The phase is in progress. Filesystem observation, manifest execution, report execution, and artifact writing are available. Ledger execution, seal execution, attachment execution, promotion execution, command materialization, status reporting, and final validation remain.

docs/PHASE_INDEX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ This index is the complete phase map for Sigtran.NET. It links each phase to the
4444
| 37 | Commercial evidence execution orchestration | [Phase 37 Commercial Evidence Execution Orchestration](PHASE37_COMMERCIAL_EVIDENCE_EXECUTION_ORCHESTRATION.md), [Phase 37 Summary](PHASE37_SUMMARY.md) | Foundation complete; real execution artifacts still required |
4545
| 38 | Commercial evidence artifact intake | [Phase 38 Commercial Evidence Artifact Intake](PHASE38_COMMERCIAL_EVIDENCE_ARTIFACT_INTAKE.md), [Phase 38 Summary](PHASE38_SUMMARY.md) | Foundation complete; real artifact files still required |
4646
| 39 | Commercial evidence file verification | [Phase 39 Commercial Evidence File Verification](PHASE39_COMMERCIAL_EVIDENCE_FILE_VERIFICATION.md), [Phase 39 Summary](PHASE39_SUMMARY.md) | Foundation complete; real retained file evidence required |
47-
| 40 | Commercial evidence filesystem execution | [Phase 40 Commercial Evidence Filesystem Execution](PHASE40_COMMERCIAL_EVIDENCE_FILESYSTEM_EXECUTION.md), [Phase 40 Summary](PHASE40_SUMMARY.md) | In progress; filesystem report execution complete |
47+
| 40 | Commercial evidence filesystem execution | [Phase 40 Commercial Evidence Filesystem Execution](PHASE40_COMMERCIAL_EVIDENCE_FILESYSTEM_EXECUTION.md), [Phase 40 Summary](PHASE40_SUMMARY.md) | In progress; filesystem artifact writing complete |
4848

4949
## Current Commercial Gate
5050

docs/SDK_ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ Status: Phase 39 is foundation-complete. Retained file evidence item verificatio
355355
- Build verification manifests, reports, retained artifacts, ledger, seal, attachments, promotion gate, and command materialization from observed files.
356356
- Keep filesystem execution separate from commercial publication: helpers can verify real files, but publication remains blocked until retained evidence comes from an approved commercial run.
357357

358-
Status: Phase 40 is in progress. Filesystem observation now reads retained files from disk, computes real SHA-256 digests, records file existence and size, and maps observations into the retained file verification model. Filesystem manifest execution now observes every promotion handoff item, supports retained-path-to-local-path overrides, and builds retained file manifests from real observations. Filesystem verification report execution now evaluates those manifests and exposes retained file blockers from real files. Retained artifact writing, ledger execution, seal execution, attachment execution, promotion execution, command materialization, status reporting, and final validation remain in progress.
358+
Status: Phase 40 is in progress. Filesystem observation now reads retained files from disk, computes real SHA-256 digests, records file existence and size, and maps observations into the retained file verification model. Filesystem manifest execution now observes every promotion handoff item, supports retained-path-to-local-path overrides, and builds retained file manifests from real observations. Filesystem verification report execution now evaluates those manifests and exposes retained file blockers from real files. Verification artifact writing now retains a Markdown report and tab-separated observation manifest on disk. Ledger execution, seal execution, attachment execution, promotion execution, command materialization, status reporting, and final validation remain in progress.
359359

360360
## Recommended First Deliverable
361361

src/Sigtran.NET.Tests/Program.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@
308308
Run("SIGTRAN commercial evidence filesystem observer computes retained file digest", SigtranCommercialEvidenceFileSystemObserverComputesRetainedFileDigest);
309309
Run("SIGTRAN commercial evidence filesystem manifest builder observes handoff files", SigtranCommercialEvidenceFileSystemManifestBuilderObservesHandoffFiles);
310310
Run("SIGTRAN commercial evidence filesystem verification report identifies missing files", SigtranCommercialEvidenceFileSystemVerificationReportIdentifiesMissingFiles);
311+
Run("SIGTRAN commercial evidence filesystem artifact writer retains reports", SigtranCommercialEvidenceFileSystemArtifactWriterRetainsReports);
311312
Run("SIGTRAN status capabilities use domain documentation labels", SigtranStatusCapabilitiesUseDomainDocumentationLabels);
312313
Run("Native SCTP platform probe reports socket creation capability", NativeSctpPlatformProbeReportsSocketCreationCapability);
313314
Run("Native SCTP socket factory creates or reports unsupported platform", NativeSctpSocketFactoryCreatesOrReportsUnsupportedPlatform);
@@ -5274,6 +5275,49 @@ static void SigtranCommercialEvidenceFileSystemVerificationReportIdentifiesMissi
52745275
}
52755276
}
52765277

5278+
static void SigtranCommercialEvidenceFileSystemArtifactWriterRetainsReports()
5279+
{
5280+
string tempRoot = Path.Combine(Path.GetTempPath(), "sigtran-commercial-evidence-" + Guid.NewGuid().ToString("N"));
5281+
Directory.CreateDirectory(tempRoot);
5282+
5283+
try
5284+
{
5285+
SigtranCommercialEvidenceFileSystemVerificationExecution execution = CreateReadyCommercialEvidenceFileSystemVerificationExecution(tempRoot);
5286+
string outputDirectory = Path.Combine(tempRoot, "verification-output");
5287+
5288+
SigtranCommercialEvidenceFileSystemArtifactWriteResult writeResult = SigtranCommercialEvidenceFileSystemArtifactWriters.WriteVerificationArtifacts(
5289+
execution,
5290+
outputDirectory,
5291+
DateTimeOffset.UtcNow);
5292+
5293+
Assert(writeResult.IsReady, writeResult.Describe());
5294+
Assert(writeResult.AllArtifactsExist, "filesystem artifact writer should create expected artifacts");
5295+
Assert(writeResult.AllArtifactsHaveContent, "filesystem artifact writer should write non-empty artifacts");
5296+
Assert(File.ReadAllText(writeResult.ReportPath).Contains("Verified: `True`", StringComparison.Ordinal), "filesystem report should render verification state");
5297+
Assert(File.ReadAllText(writeResult.ObservationManifestPath).Contains("actualSha256", StringComparison.Ordinal), "filesystem observations should include digest column");
5298+
}
5299+
finally
5300+
{
5301+
DeleteTempEvidenceRoot(tempRoot);
5302+
}
5303+
}
5304+
5305+
static SigtranCommercialEvidenceFileSystemVerificationExecution CreateReadyCommercialEvidenceFileSystemVerificationExecution(string tempRoot)
5306+
{
5307+
byte[] artifactContent = "verified commercial artifact"u8.ToArray();
5308+
byte[] reportContent = "verified commercial readiness report"u8.ToArray();
5309+
SigtranCommercialEvidencePromotionHandoff handoff = CreateCommercialEvidencePromotionHandoffWithDigests(
5310+
ComputeSha256Hex(artifactContent),
5311+
ComputeSha256Hex(reportContent));
5312+
IReadOnlyDictionary<string, string> pathOverrides = MaterializeHandoffFiles(tempRoot, handoff, artifactContent, reportContent);
5313+
SigtranCommercialEvidenceFileSystemManifestExecution manifestExecution = SigtranCommercialEvidenceFileSystemManifestBuilder.Build(
5314+
handoff,
5315+
pathOverrides,
5316+
DateTimeOffset.UtcNow);
5317+
5318+
return SigtranCommercialEvidenceFileSystemVerificationReports.Evaluate(manifestExecution);
5319+
}
5320+
52775321
static IReadOnlyDictionary<string, string> MaterializeHandoffFiles(
52785322
string tempRoot,
52795323
SigtranCommercialEvidencePromotionHandoff handoff,
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
namespace Sigtran.NET.Core.Utilities;
2+
3+
/// <summary>
4+
/// Describes retained filesystem verification artifacts written to disk.
5+
/// </summary>
6+
public sealed class SigtranCommercialEvidenceFileSystemArtifactWriteResult
7+
{
8+
/// <summary>Creates a retained filesystem verification artifact write result.</summary>
9+
/// <param name="verificationExecution">The filesystem verification execution.</param>
10+
/// <param name="outputDirectory">The output directory.</param>
11+
/// <param name="reportPath">The written verification report path.</param>
12+
/// <param name="observationManifestPath">The written observation manifest path.</param>
13+
/// <param name="writtenAtUtc">The UTC write time.</param>
14+
public SigtranCommercialEvidenceFileSystemArtifactWriteResult(
15+
SigtranCommercialEvidenceFileSystemVerificationExecution verificationExecution,
16+
string outputDirectory,
17+
string reportPath,
18+
string observationManifestPath,
19+
DateTimeOffset writtenAtUtc)
20+
{
21+
VerificationExecution = verificationExecution ?? throw new ArgumentNullException(nameof(verificationExecution));
22+
OutputDirectory = string.IsNullOrWhiteSpace(outputDirectory) ? throw new ArgumentException("Output directory is required.", nameof(outputDirectory)) : outputDirectory;
23+
ReportPath = string.IsNullOrWhiteSpace(reportPath) ? throw new ArgumentException("Report path is required.", nameof(reportPath)) : reportPath;
24+
ObservationManifestPath = string.IsNullOrWhiteSpace(observationManifestPath) ? throw new ArgumentException("Observation manifest path is required.", nameof(observationManifestPath)) : observationManifestPath;
25+
WrittenAtUtc = writtenAtUtc.Offset == TimeSpan.Zero ? writtenAtUtc : writtenAtUtc.ToUniversalTime();
26+
}
27+
28+
/// <summary>The filesystem verification execution.</summary>
29+
public SigtranCommercialEvidenceFileSystemVerificationExecution VerificationExecution { get; }
30+
31+
/// <summary>The output directory.</summary>
32+
public string OutputDirectory { get; }
33+
34+
/// <summary>The written verification report path.</summary>
35+
public string ReportPath { get; }
36+
37+
/// <summary>The written observation manifest path.</summary>
38+
public string ObservationManifestPath { get; }
39+
40+
/// <summary>The UTC write time.</summary>
41+
public DateTimeOffset WrittenAtUtc { get; }
42+
43+
/// <summary>Whether all expected artifacts exist.</summary>
44+
public bool AllArtifactsExist => File.Exists(ReportPath)
45+
&& File.Exists(ObservationManifestPath);
46+
47+
/// <summary>Whether all expected artifacts have non-empty content.</summary>
48+
public bool AllArtifactsHaveContent => AllArtifactsExist
49+
&& new FileInfo(ReportPath).Length > 0
50+
&& new FileInfo(ObservationManifestPath).Length > 0;
51+
52+
/// <summary>Whether the write time is normalized to UTC.</summary>
53+
public bool UsesUtcWriteTime => WrittenAtUtc.Offset == TimeSpan.Zero;
54+
55+
/// <summary>Whether retained filesystem verification artifacts are ready for ledger execution.</summary>
56+
public bool IsReady => VerificationExecution.IsReady
57+
&& AllArtifactsExist
58+
&& AllArtifactsHaveContent
59+
&& UsesUtcWriteTime;
60+
61+
/// <summary>Formats a compact artifact write summary.</summary>
62+
/// <returns>The artifact write summary.</returns>
63+
public string Describe()
64+
{
65+
return $"commercialEvidenceFileSystemArtifactsReady={IsReady} report={ReportPath} observations={ObservationManifestPath}";
66+
}
67+
}
68+
69+
/// <summary>
70+
/// Writes retained filesystem verification artifacts to disk.
71+
/// </summary>
72+
public static class SigtranCommercialEvidenceFileSystemArtifactWriters
73+
{
74+
/// <summary>Writes the filesystem verification report and observation manifest.</summary>
75+
/// <param name="verificationExecution">The filesystem verification execution.</param>
76+
/// <param name="outputDirectory">The output directory.</param>
77+
/// <param name="writtenAtUtc">An optional UTC write time.</param>
78+
/// <returns>The retained filesystem verification artifact write result.</returns>
79+
public static SigtranCommercialEvidenceFileSystemArtifactWriteResult WriteVerificationArtifacts(
80+
SigtranCommercialEvidenceFileSystemVerificationExecution verificationExecution,
81+
string outputDirectory,
82+
DateTimeOffset? writtenAtUtc = null)
83+
{
84+
ArgumentNullException.ThrowIfNull(verificationExecution);
85+
if (string.IsNullOrWhiteSpace(outputDirectory))
86+
{
87+
throw new ArgumentException("Output directory is required.", nameof(outputDirectory));
88+
}
89+
90+
Directory.CreateDirectory(outputDirectory);
91+
string reportPath = Path.Combine(outputDirectory, "filesystem-verification-report.md");
92+
string observationManifestPath = Path.Combine(outputDirectory, "filesystem-observations.tsv");
93+
File.WriteAllText(reportPath, RenderReport(verificationExecution));
94+
File.WriteAllText(observationManifestPath, RenderObservations(verificationExecution.ManifestExecution.Observations));
95+
96+
return new(
97+
verificationExecution,
98+
outputDirectory,
99+
reportPath,
100+
observationManifestPath,
101+
writtenAtUtc ?? DateTimeOffset.UtcNow);
102+
}
103+
104+
private static string RenderReport(SigtranCommercialEvidenceFileSystemVerificationExecution execution)
105+
{
106+
return string.Join(
107+
Environment.NewLine,
108+
[
109+
"# Commercial Evidence Filesystem Verification Report",
110+
string.Empty,
111+
$"Intake: `{execution.ManifestExecution.Handoff.Report.Target.IntakeId}`",
112+
$"Observations: `{execution.ObservationCount}`",
113+
$"Filesystem evidence: `{execution.HasFilesystemEvidence}`",
114+
$"Verified: `{execution.Report.IsVerified}`",
115+
$"Missing files: `{execution.Report.MissingFileCount}`",
116+
$"Digest mismatches: `{execution.Report.DigestMismatchCount}`",
117+
$"Blockers: `{string.Join(",", execution.Report.Blockers)}`"
118+
]);
119+
}
120+
121+
private static string RenderObservations(IReadOnlyList<SigtranCommercialEvidenceFileSystemObservation> observations)
122+
{
123+
string[] lines = observations
124+
.Select(static observation => string.Join(
125+
'\t',
126+
observation.RetainedFile.Kind,
127+
observation.RetainedFile.RetainedPath,
128+
observation.FileSystemPath,
129+
observation.Exists,
130+
observation.RetainedFile.SizeBytes,
131+
observation.RetainedFile.ActualSha256,
132+
observation.RetainedFile.DigestMatches))
133+
.Prepend("kind\tretainedPath\tfileSystemPath\texists\tsizeBytes\tactualSha256\tdigestMatches")
134+
.ToArray();
135+
136+
return string.Join(Environment.NewLine, lines);
137+
}
138+
}

0 commit comments

Comments
 (0)