Skip to content

Commit 854d035

Browse files
committed
Merge branch 'dev'
2 parents da294c5 + 93f8334 commit 854d035

19 files changed

Lines changed: 4104 additions & 0 deletions
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/** @file CanonicalHash.hpp
2+
* Deterministic format-1 structural encoding and SHA-256 helpers.
3+
* Callers must supply semantically normalized values.
4+
*/
5+
#ifndef VIX_CLI_PROJECT_NATIVE_CANONICAL_HASH_HPP
6+
#define VIX_CLI_PROJECT_NATIVE_CANONICAL_HASH_HPP
7+
8+
#include <string>
9+
#include <string_view>
10+
#include <variant>
11+
#include <vector>
12+
13+
#include <vix/cli/project/native/Models.hpp>
14+
15+
namespace vix::cli::project::native
16+
{
17+
struct RegistryNodeIdentity
18+
{
19+
RegistryPackageIdentity package;
20+
Version version;
21+
};
22+
23+
struct GitNodeIdentity
24+
{
25+
std::string normalizedRepository;
26+
std::string commit;
27+
};
28+
29+
struct NormalizedRootGitRequirement
30+
{
31+
std::string normalizedRepository;
32+
GitRevisionRequirement revision;
33+
};
34+
35+
struct RootRequirementDigestEntry
36+
{
37+
std::string alias;
38+
std::variant<NormalizedDeclaredRegistry, NormalizedRootGitRequirement> declared;
39+
};
40+
41+
[[nodiscard]] std::string canonical_registry_node_bytes(const RegistryNodeIdentity &identity);
42+
[[nodiscard]] std::string canonical_git_node_bytes(const GitNodeIdentity &identity);
43+
[[nodiscard]] std::string registry_node_id(const RegistryNodeIdentity &identity);
44+
[[nodiscard]] std::string git_node_id(const GitNodeIdentity &identity);
45+
46+
[[nodiscard]] std::string canonical_root_requirements_bytes(
47+
const std::vector<RootRequirementDigestEntry> &requirements);
48+
[[nodiscard]] std::string root_requirements_digest(
49+
const std::vector<RootRequirementDigestEntry> &requirements);
50+
51+
// Returns 64 lowercase hexadecimal digits without an algorithm prefix.
52+
[[nodiscard]] std::string sha256_hex(std::string_view bytes);
53+
// Returns the persistent format representation: sha256:<lowercase hex>.
54+
[[nodiscard]] std::string sha256_digest(std::string_view bytes);
55+
} // namespace vix::cli::project::native
56+
57+
#endif // VIX_CLI_PROJECT_NATIVE_CANONICAL_HASH_HPP
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/** @file Lockfile.hpp
2+
* Structural lockfile integrity and deterministic format-1 text serialization.
3+
*/
4+
#ifndef VIX_CLI_PROJECT_NATIVE_LOCKFILE_HPP
5+
#define VIX_CLI_PROJECT_NATIVE_LOCKFILE_HPP
6+
7+
#include <optional>
8+
#include <string>
9+
#include <vector>
10+
11+
#include <vix/cli/project/native/Models.hpp>
12+
#include <vix/cli/project/native/Validation.hpp>
13+
14+
namespace vix::cli::project::native
15+
{
16+
enum class LockfileIntegrityCode
17+
{
18+
root_requirements_digest_mismatch,
19+
node_id_mismatch
20+
};
21+
22+
struct LockfileIntegrityIssue
23+
{
24+
LockfileIntegrityCode code{LockfileIntegrityCode::node_id_mismatch};
25+
std::string subject;
26+
std::string message;
27+
std::string storedValue;
28+
std::string expectedValue;
29+
};
30+
31+
struct LockfileIntegrityResult
32+
{
33+
std::vector<LockfileIntegrityIssue> issues;
34+
[[nodiscard]] bool valid() const noexcept { return issues.empty(); }
35+
};
36+
37+
[[nodiscard]] LockfileIntegrityResult validate_lockfile_integrity(const Lockfile &lockfile);
38+
39+
enum class LockfileSerializationIssueKind
40+
{
41+
semantic_validation,
42+
integrity
43+
};
44+
45+
struct LockfileSerializationIssue
46+
{
47+
LockfileSerializationIssueKind kind{LockfileSerializationIssueKind::semantic_validation};
48+
std::string subject;
49+
std::string message;
50+
std::optional<ValidationCode> validationCode;
51+
std::optional<LockfileIntegrityCode> integrityCode;
52+
std::string storedValue;
53+
std::string expectedValue;
54+
};
55+
56+
struct LockfileSerializationResult
57+
{
58+
std::optional<std::string> text;
59+
std::vector<LockfileSerializationIssue> issues;
60+
[[nodiscard]] bool valid() const noexcept { return text.has_value() && issues.empty(); }
61+
};
62+
63+
// Serialization validates semantics and structural integrity. It never
64+
// repairs stored IDs/digests or writes files.
65+
[[nodiscard]] LockfileSerializationResult serialize_lockfile(const Lockfile &lockfile);
66+
} // namespace vix::cli::project::native
67+
68+
#endif // VIX_CLI_PROJECT_NATIVE_LOCKFILE_HPP
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/** @file MetadataAcquisition.hpp
2+
* Synchronous metadata observation and transitive catalog acquisition.
3+
*/
4+
#ifndef VIX_CLI_PROJECT_NATIVE_METADATA_ACQUISITION_HPP
5+
#define VIX_CLI_PROJECT_NATIVE_METADATA_ACQUISITION_HPP
6+
7+
#include <optional>
8+
#include <string>
9+
#include <vector>
10+
11+
#include <vix/cli/project/native/ResolutionCatalog.hpp>
12+
13+
namespace vix::cli::project::native
14+
{
15+
struct RegistryQueryResult
16+
{
17+
bool succeeded{true};
18+
std::vector<RegistryCandidate> releases;
19+
std::string diagnostic;
20+
};
21+
22+
enum class GitQueryStatus { found, not_found, failed };
23+
24+
struct GitQueryResult
25+
{
26+
GitQueryStatus status{GitQueryStatus::not_found};
27+
std::optional<GitResolution> resolution;
28+
std::string diagnostic;
29+
};
30+
31+
// Semantic metadata boundary only. Implementations do not expose transport,
32+
// Git, filesystem, cache, or package-content operations here. A future
33+
// metadata cache (versions/contracts/revision observations) is distinct from
34+
// the later store of immutable package bytes; neither is implemented here.
35+
class PackageMetadataSource
36+
{
37+
public:
38+
virtual ~PackageMetadataSource() = default;
39+
[[nodiscard]] virtual RegistryQueryResult registry_releases(
40+
const RegistryPackageIdentity &identity) = 0;
41+
[[nodiscard]] virtual GitQueryResult resolve_git(
42+
const GitPackageIdentity &identity,
43+
const GitRevisionRequirement &revision) = 0;
44+
};
45+
46+
enum class MetadataAcquisitionErrorCode
47+
{
48+
registry_source_failure,
49+
git_source_failure,
50+
catalog_construction_failure,
51+
invalid_source_response
52+
};
53+
54+
struct MetadataAcquisitionIssue
55+
{
56+
MetadataAcquisitionErrorCode code{MetadataAcquisitionErrorCode::invalid_source_response};
57+
std::string subject;
58+
std::string message;
59+
std::optional<ResolutionCatalogErrorCode> catalogCode;
60+
};
61+
62+
struct MetadataAcquisitionResult
63+
{
64+
std::optional<ResolutionCatalog> catalog;
65+
std::vector<MetadataAcquisitionIssue> issues;
66+
[[nodiscard]] bool valid() const noexcept { return catalog.has_value() && issues.empty(); }
67+
};
68+
69+
// Observes all transitive metadata reachable from root declarations. Registry
70+
// queries return complete observed release sets; no requirement filtering or
71+
// package-content acquisition occurs in this layer.
72+
[[nodiscard]] MetadataAcquisitionResult acquire_resolution_catalog(
73+
const std::vector<PackageRequirement> &rootRequirements,
74+
PackageMetadataSource &source);
75+
} // namespace vix::cli::project::native
76+
77+
#endif // VIX_CLI_PROJECT_NATIVE_METADATA_ACQUISITION_HPP
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/** @file ProjectLockState.hpp
2+
* Pure classification of project package requirements against an optional lock.
3+
*/
4+
#ifndef VIX_CLI_PROJECT_NATIVE_PROJECT_LOCK_STATE_HPP
5+
#define VIX_CLI_PROJECT_NATIVE_PROJECT_LOCK_STATE_HPP
6+
7+
#include <optional>
8+
#include <string>
9+
#include <vector>
10+
11+
#include <vix/cli/project/native/Lockfile.hpp>
12+
#include <vix/cli/project/native/Models.hpp>
13+
14+
namespace vix::cli::project::native
15+
{
16+
enum class ProjectLockState
17+
{
18+
not_required,
19+
missing,
20+
current,
21+
stale,
22+
invalid,
23+
unnecessary
24+
};
25+
26+
enum class ProjectLockIssueSource
27+
{
28+
lock_semantics,
29+
lock_integrity
30+
};
31+
32+
struct ProjectLockIssue
33+
{
34+
ProjectLockIssueSource source{ProjectLockIssueSource::lock_semantics};
35+
std::string subject;
36+
std::string message;
37+
std::optional<ValidationCode> validationCode;
38+
std::optional<LockfileIntegrityCode> integrityCode;
39+
std::string storedValue;
40+
std::string expectedValue;
41+
};
42+
43+
struct ProjectLockStatus
44+
{
45+
ProjectLockState state{ProjectLockState::not_required};
46+
std::optional<std::string> expectedRequirementsDigest;
47+
std::optional<std::string> storedRequirementsDigest;
48+
std::vector<ProjectLockIssue> issues;
49+
};
50+
51+
// The project must already have passed validate_native_project(). This pure
52+
// operation performs no filesystem access, resolution, or lock mutation.
53+
[[nodiscard]] std::string project_requirements_digest(const NativeProject &project);
54+
[[nodiscard]] ProjectLockStatus evaluate_project_lock_state(
55+
const NativeProject &project, const std::optional<Lockfile> &lockfile);
56+
} // namespace vix::cli::project::native
57+
58+
#endif // VIX_CLI_PROJECT_NATIVE_PROJECT_LOCK_STATE_HPP
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/** @file ResolutionCatalog.hpp
2+
* Immutable in-memory metadata snapshot for deterministic package resolution.
3+
*/
4+
#ifndef VIX_CLI_PROJECT_NATIVE_RESOLUTION_CATALOG_HPP
5+
#define VIX_CLI_PROJECT_NATIVE_RESOLUTION_CATALOG_HPP
6+
7+
#include <optional>
8+
#include <string>
9+
#include <vector>
10+
11+
#include <vix/cli/project/native/Resolver.hpp>
12+
13+
namespace vix::cli::project::native
14+
{
15+
enum class ResolutionCatalogErrorCode
16+
{
17+
invalid_contract,
18+
registry_contract_identity_mismatch,
19+
registry_contract_version_mismatch,
20+
invalid_git_contract_source,
21+
invalid_repository_identity,
22+
invalid_content_digest,
23+
duplicate_registry_release,
24+
conflicting_registry_release,
25+
duplicate_git_revision,
26+
conflicting_git_revision,
27+
conflicting_git_commit_metadata
28+
};
29+
30+
struct ResolutionCatalogIssue
31+
{
32+
ResolutionCatalogErrorCode code{ResolutionCatalogErrorCode::invalid_contract};
33+
std::string subject;
34+
std::string message;
35+
};
36+
37+
struct ResolutionCatalogBuildResult;
38+
39+
class ResolutionCatalog final : public ResolutionMetadataProvider
40+
{
41+
public:
42+
[[nodiscard]] std::vector<RegistryCandidate> registry_candidates(
43+
const RegistryPackageIdentity &identity) const override;
44+
[[nodiscard]] std::vector<GitResolution> git_resolutions(
45+
const std::string &normalizedRepository,
46+
const GitRevisionRequirement &revision) const override;
47+
48+
private:
49+
friend struct ResolutionCatalogBuildResult;
50+
friend ResolutionCatalogBuildResult build_resolution_catalog(
51+
std::vector<RegistryCandidate>, std::vector<GitResolution>);
52+
53+
ResolutionCatalog(std::vector<RegistryCandidate> registry, std::vector<GitResolution> git);
54+
55+
std::vector<RegistryCandidate> registry_;
56+
std::vector<GitResolution> git_;
57+
};
58+
59+
struct ResolutionCatalogBuildResult
60+
{
61+
std::optional<ResolutionCatalog> value;
62+
std::vector<ResolutionCatalogIssue> issues;
63+
[[nodiscard]] bool valid() const noexcept { return value.has_value() && issues.empty(); }
64+
};
65+
66+
// Builds a finalized value snapshot. Duplicate immutable keys and conflicting
67+
// Git commit metadata are errors; insertion order never selects a winner.
68+
[[nodiscard]] ResolutionCatalogBuildResult build_resolution_catalog(
69+
std::vector<RegistryCandidate> registry,
70+
std::vector<GitResolution> git);
71+
} // namespace vix::cli::project::native
72+
73+
#endif // VIX_CLI_PROJECT_NATIVE_RESOLUTION_CATALOG_HPP

0 commit comments

Comments
 (0)