commit 66b603cf145bbb4ade64da622e440daedb4776c8
parent b3da37d0881d2c54d1a90811b8c001c455d9f9de
Author: triesap <tyson@radroots.org>
Date: Sun, 9 Aug 2026 18:07:55 +0000
core: complete local Rust ownership
- remove the superseded source-lock crate manifest and consumer marker
- build native libraries and UniFFI bindings directly from HarvestCircle core
- align workspace lint policy with the imported producer contract
- rename the Gradle root and retain immutable shared Radroots Git edges
Diffstat:
9 files changed, 36 insertions(+), 165 deletions(-)
diff --git a/.radroots-consumer-root b/.radroots-consumer-root
@@ -1 +0,0 @@
-studio
diff --git a/AGENTS.md b/AGENTS.md
@@ -28,10 +28,6 @@ absolute host paths, or an enclosing monorepo layout.
- `core/Cargo.toml`, `core/Cargo.lock`, `core/rust-toolchain.toml`, and the
product crates under `core/crates/**` own the Rust workspace inputs.
-- While the ownership migration is in progress,
- `radroots.lib.source-lock.v1.toml` and `.radroots-consumer-root` remain
- transitional inputs. Remove them, the source-lock placeholder crate, and
- external Studio crate edges once every product crate is local and green.
- Gradle settings, build scripts, the version catalog, wrapper properties,
policy configuration, and `core/compatibility/v5-baseline.properties` own
the desktop build, dependency, compatibility, and package inputs. Kotlin and
@@ -47,8 +43,8 @@ absolute host paths, or an enclosing monorepo layout.
agree.
- Never use a path dependency, floating branch or tag, private mirror,
implicit sibling override, dirty source cache, or unrecorded native binary.
- A local commit is not a release input until it is publicly reachable and its
- governed source-lock evidence verifies.
+ Local product crates are workspace path dependencies; shared Radroots
+ packages remain immutable public Git dependencies.
- Human specifications, decisions, runbooks, migration history, qualification
records, and execution evidence are parent-owned and absent from standalone
clones. Physical or tracked `docs/**`, `.github/**`, and `.act/**` roots are
@@ -85,8 +81,8 @@ check in generated bindings or native binaries as a source substitute.
## Change and command rules
-Inspect status, all relevant manifests and locks, source-lock and compatibility
-inputs, Gradle tasks, native generation logic, source, tests, and package
+Inspect status, all relevant manifests and locks, compatibility inputs, Gradle
+tasks, native generation logic, source, tests, and package
configuration before editing. Make one coherent, reviewable change at a time;
keep implementation, tests, generated outputs, dependency evidence, and public
behavior aligned while preserving unrelated work.
@@ -107,8 +103,8 @@ silently switch sources when offline. Never claim a lane passed unless it ran
successfully; report network, toolchain, platform, advisory-service, package,
or external-artifact blockers exactly.
-Verify exact source-lock/manifests/lock agreement, generated binding and native
-artifact freshness when affected, compatibility and architecture guards,
+Verify exact manifests/lock agreement, generated binding and native artifact
+freshness when affected, compatibility and architecture guards,
license/source policy, zero forbidden roots, `git diff --check`, and final
status and diff. Do not treat parent-only workflow proof as a substitute for
standalone repository validation.
diff --git a/app/desktop/build.gradle.kts b/app/desktop/build.gradle.kts
@@ -86,24 +86,29 @@ val immutableCargoArguments =
listOf("--locked")
}
-val sourceLockFile = rootProject.layout.projectDirectory.file("radroots.lib.source-lock.v1.toml")
-
-fun sourceLockValue(key: String): String {
+val rustCoreSource =
+ rootProject.layout.projectDirectory
+ .dir("core")
+ .asFile
+val rustManifest = rustCoreSource.resolve("Cargo.toml")
+
+fun workspacePackageValue(key: String): String {
+ val workspacePackage =
+ rustManifest
+ .readText()
+ .substringAfter("[workspace.package]", missingDelimiterValue = "")
+ .substringBefore("\n[")
+ require(workspacePackage.isNotBlank()) { "Cargo manifest is missing [workspace.package]" }
val expression = Regex("""(?m)^${Regex.escape(key)}\s*=\s*"([^"]+)"\s*$""")
return expression
- .find(sourceLockFile.asFile.readText())
+ .find(workspacePackage)
?.groupValues
?.get(1)
- ?: throw GradleException("Source lock is missing $key")
+ ?: throw GradleException("Cargo workspace package metadata is missing $key")
}
-val radrootsLibRepository = sourceLockValue("repository")
-val radrootsLibRevision = sourceLockValue("revision")
-val radrootsLibVersion = sourceLockValue("version")
-val radrootsLibSource = file(extBuildGradleRoot).resolve("source/lib")
-val rustManifest = radrootsLibSource.resolve("Cargo.toml")
val compatibilityBaseline = rootProject.layout.projectDirectory.file("core/compatibility/v5-baseline.properties")
-val appVersion = radrootsLibVersion
+val appVersion = workspacePackageValue("version")
val macOsBuildVersion = "1"
val baseline =
Properties().apply {
@@ -127,102 +132,17 @@ val applicationNamespace = baselineValue("package.namespace")
version = appVersion
val rustSources =
- fileTree(radrootsLibSource) {
+ fileTree(rustCoreSource) {
include(
"Cargo.toml",
"Cargo.lock",
"rust-toolchain.toml",
- "contracts/crates/catalog.v1.toml",
+ "compatibility/**",
"crates/studio_*/**",
- "tools/xtask/**",
)
exclude("target/**")
}
-abstract class SyncRadrootsLibSource : DefaultTask() {
- @get:Input
- abstract val repository: Property<String>
-
- @get:Input
- abstract val revision: Property<String>
-
- @get:Input
- abstract val offline: Property<Boolean>
-
- @get:OutputDirectory
- abstract val sourceDirectory: DirectoryProperty
-
- @TaskAction
- fun sync() {
- val source = sourceDirectory.get().asFile
- if (!source.resolve(".git").isDirectory) {
- require(!offline.get()) { "Canonical source is not cached and offline mode is enabled" }
- source.parentFile.mkdirs()
- command(source.parentFile, "git", "clone", "--filter=blob:none", "--no-checkout", repository.get(), source.absolutePath)
- }
- require(command(source, "git", "remote", "get-url", "origin").trim() == repository.get()) {
- "Canonical source cache origin does not match the source lock"
- }
- if (!offline.get()) {
- command(source, "git", "fetch", "--force", "--no-tags", "origin", revision.get())
- }
- command(source, "git", "cat-file", "-e", "${revision.get()}^{commit}")
- command(source, "git", "checkout", "--detach", revision.get())
- require(command(source, "git", "rev-parse", "HEAD").trim() == revision.get()) {
- "Materialized source revision does not match the source lock"
- }
- require(command(source, "git", "status", "--porcelain", "--untracked-files=all").isBlank()) {
- "Materialized source tree is not clean"
- }
- }
-
- private fun command(
- workingDirectory: File,
- vararg command: String,
- ): String {
- val process =
- ProcessBuilder(*command)
- .directory(workingDirectory)
- .redirectErrorStream(true)
- .start()
- val output = process.inputStream.bufferedReader().use { it.readText() }
- require(process.waitFor() == 0) {
- "${command.joinToString(" ")} failed: ${output.trim()}"
- }
- return output
- }
-}
-
-val syncRadrootsLibSource by tasks.registering(SyncRadrootsLibSource::class) {
- repository.set(radrootsLibRepository)
- revision.set(radrootsLibRevision)
- offline.set(
- radrootsOffline,
- )
- sourceDirectory.set(radrootsLibSource)
- outputs.upToDateWhen { false }
-}
-
-val validateRadrootsSourceLock by tasks.registering(Exec::class) {
- dependsOn(syncRadrootsLibSource)
- workingDir(radrootsLibSource)
- commandLine(
- "cargo",
- "run",
- "--manifest-path",
- rustManifest.absolutePath,
- "-p",
- "xtask",
- *immutableCargoArguments.toTypedArray(),
- "--",
- "source-lock",
- "--consumer-root",
- rootProject.projectDir.absolutePath,
- )
- inputs.file(sourceLockFile)
- inputs.file(rootProject.layout.projectDirectory.file("core/Cargo.lock"))
-}
-
data class NativeTarget(
val libraryName: String,
val jnaPrefix: String,
@@ -263,8 +183,7 @@ val rustReleaseLibrary = file(cargoTargetRoot).resolve("release/$rustLibraryName
val jnaPlatformPrefix = nativeTarget.jnaPrefix
val buildRustCoreDebug by tasks.registering(Exec::class) {
- dependsOn(validateRadrootsSourceLock)
- workingDir(radrootsLibSource)
+ workingDir(rustCoreSource)
commandLine(
"cargo",
"build",
@@ -274,14 +193,12 @@ val buildRustCoreDebug by tasks.registering(Exec::class) {
"radroots_studio_ffi",
*immutableCargoArguments.toTypedArray(),
)
- environment("RADROOTS_SOURCE_SHA", radrootsLibRevision)
inputs.files(rustSources)
outputs.file(rustDebugLibrary)
}
val buildRustCoreRelease by tasks.registering(Exec::class) {
- dependsOn(validateRadrootsSourceLock)
- workingDir(radrootsLibSource)
+ workingDir(rustCoreSource)
commandLine(
"cargo",
"build",
@@ -292,7 +209,6 @@ val buildRustCoreRelease by tasks.registering(Exec::class) {
"radroots_studio_ffi",
*immutableCargoArguments.toTypedArray(),
)
- environment("RADROOTS_SOURCE_SHA", radrootsLibRevision)
inputs.files(rustSources)
outputs.file(rustReleaseLibrary)
}
@@ -304,7 +220,7 @@ val cleanGeneratedUniFfiKotlin by tasks.registering(Delete::class) {
}
val generateUniFfiKotlin by tasks.registering(Exec::class) {
dependsOn(buildRustCoreDebug, cleanGeneratedUniFfiKotlin)
- workingDir(radrootsLibSource)
+ workingDir(rustCoreSource)
commandLine(
"cargo",
"run",
@@ -321,13 +237,13 @@ val generateUniFfiKotlin by tasks.registering(Exec::class) {
"--metadata-no-deps",
"--no-format",
"--config",
- radrootsLibSource.resolve("crates/studio_ffi/uniffi.toml").absolutePath,
+ rustCoreSource.resolve("crates/studio_ffi/uniffi.toml").absolutePath,
"--out-dir",
generatedUniFfiKotlin.get().asFile.absolutePath,
rustDebugLibrary.absolutePath,
)
inputs.file(rustDebugLibrary)
- inputs.file(radrootsLibSource.resolve("crates/studio_ffi/uniffi.toml"))
+ inputs.file(rustCoreSource.resolve("crates/studio_ffi/uniffi.toml"))
outputs.dir(generatedUniFfiKotlin)
}
diff --git a/core/Cargo.lock b/core/Cargo.lock
@@ -2081,19 +2081,6 @@ dependencies = [
]
[[package]]
-name = "radroots_studio_source_lock"
-version = "0.1.0-alpha"
-dependencies = [
- "radroots_studio_application",
- "radroots_studio_domain",
- "radroots_studio_ffi",
- "radroots_studio_nostr",
- "radroots_studio_preferences",
- "radroots_studio_runtime",
- "radroots_studio_storage",
-]
-
-[[package]]
name = "radroots_studio_storage"
version = "0.1.0-alpha"
dependencies = [
diff --git a/core/Cargo.toml b/core/Cargo.toml
@@ -1,6 +1,5 @@
[workspace]
members = [
- "crates/source_lock",
"crates/studio_application",
"crates/studio_domain",
"crates/studio_ffi",
@@ -25,9 +24,13 @@ authors = ["Tyson Lupul <tyson@radroots.org>"]
unsafe_code = "forbid"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] }
+[workspace.lints.rustdoc]
+broken_intra_doc_links = "deny"
+
[workspace.lints.clippy]
-all = "deny"
-pedantic = "deny"
+dbg_macro = "deny"
+todo = "deny"
+unimplemented = "deny"
[workspace.dependencies]
radroots_studio_application = { path = "crates/studio_application", version = "=0.1.0-alpha" }
diff --git a/core/crates/source_lock/Cargo.toml b/core/crates/source_lock/Cargo.toml
@@ -1,20 +0,0 @@
-[package]
-name = "radroots_studio_source_lock"
-version.workspace = true
-edition.workspace = true
-rust-version.workspace = true
-license.workspace = true
-repository.workspace = true
-publish = false
-
-[dependencies]
-radroots_studio_application.workspace = true
-radroots_studio_domain.workspace = true
-radroots_studio_ffi.workspace = true
-radroots_studio_nostr.workspace = true
-radroots_studio_preferences.workspace = true
-radroots_studio_runtime.workspace = true
-radroots_studio_storage.workspace = true
-
-[lints]
-workspace = true
diff --git a/core/crates/source_lock/src/lib.rs b/core/crates/source_lock/src/lib.rs
@@ -1 +0,0 @@
-#![no_std]
diff --git a/radroots.lib.source-lock.v1.toml b/radroots.lib.source-lock.v1.toml
@@ -1,9 +0,0 @@
-schema = "radroots.lib.source-lock.v1"
-repository = "https://github.com/radrootslabs/lib"
-revision = "09065a610d95e57acdc895a14c07580fa099e7c3"
-architecture = "radroots.crates.release.v2"
-workspace_catalog_sha256 = "8c27cebf6825f9ed74e122513c661f6dd31837dddb39d0988014121d8ab05e75"
-version = "0.1.0-alpha"
-source_archive_sha256 = "68badd1fb02d9396682d368e62dfe79969d8da48529760789c823fb4ab54aea3"
-lockfile = "core/Cargo.lock"
-lockfile_sha256 = "f84789b2a890ae3cd082dbce464adb582c4ebd4dcebedf52c2381476294f633a"
diff --git a/settings.gradle.kts b/settings.gradle.kts
@@ -37,7 +37,7 @@ plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
-rootProject.name = "studio_app"
+rootProject.name = "harvestcircle"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")