Skip to content

Add durable self-dev customization records#187

Open
aayu22809 wants to merge 4 commits into
1jehuang:masterfrom
aayu22809:selfdev-customization-records
Open

Add durable self-dev customization records#187
aayu22809 wants to merge 4 commits into
1jehuang:masterfrom
aayu22809:selfdev-customization-records

Conversation

@aayu22809
Copy link
Copy Markdown

@aayu22809 aayu22809 commented May 11, 2026

Summary

Adds durable self-dev customization records so Jcode can persist, inspect, and report user-local adaptations across update/install flows.

This PR implements the first self-dev customization slice from #32 and addresses issues #35, #36, and #37:

  • Defines a versioned SelfDevCustomizationRecord schema with stable IDs, timestamps, active/disabled state, base version metadata, provenance, rationale, validation commands, and update hints.
  • Persists customization records to stable on-disk storage with create/load/list/append-outcome support.
  • Adds selfdev tool actions for recording, listing, disabling, and inspecting active customizations.
  • Captures both tracked diffs and untracked files in saved customization patches so the source fingerprint and stored patch match more accurately.
  • Integrates active customization records into update/install reporting.
  • Runs configured validation commands during update/install reporting and records report-only pass/fail details, including status, exit code, and truncated stdout/stderr.
  • Cleans up compact active-customization memory when a customization is disabled while keeping durable records as the source of truth.

Fixes #35
Fixes #36
Fixes #37

Testing

Passed on the rebased branch:

cargo test -p jcode-selfdev-types -p jcode-build-support customization --lib
cargo test record_customization_creates_record_and_list_output --lib
cargo test disable_customization_removes_compact_memory_and_active_status --lib
cargo test update_validation_command_reports_success --lib
cargo test update_validation_command_reports_failure --lib
cargo check
cargo build

Notes:

  • cargo check and cargo build pass with existing warnings.
  • A broad cargo test selfdev --lib run hit two unrelated/flaky failures on macOS:
    • cli::tui_launch::tests::spawn_selfdev_in_new_terminal_uses_handterm_exec_mode due to /private/var vs /var temp path normalization.
    • tool::selfdev::tests::build_dedupes_identical_reason_and_version_with_attached_watcher due to a background task timeout.
  • The targeted customization/update validation coverage added by this PR passed after rebasing onto origin/master.

View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Copilot AI review requested due to automatic review settings May 11, 2026 02:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a first durable “self-dev customization record” slice so Jcode can persist user-local customizations (including metadata and patch provenance), expose them via selfdev tool actions, and incorporate active customizations into update/install reporting (including optional validation command execution with recorded outcomes).

Changes:

  • Add versioned SelfDevCustomizationRecord types plus build-support helpers to persist/list/disable records and append outcomes.
  • Add selfdev actions to record/list/inspect/disable customizations and surface active customizations in selfdev status.
  • Integrate active customizations into update/install flows by recording “needs review” or running validation commands and storing pass/fail output.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/update.rs Records per-customization update outcomes and runs validation commands during update/install reporting.
src/tool/selfdev/mod.rs Extends the selfdev tool schema/actions to include customization record operations.
src/tool/selfdev/customization.rs Implements record/list/inspect/disable customization actions and compact-memory integration.
src/tool/selfdev/status.rs Displays active customization records in selfdev status output.
src/tool/selfdev/tests.rs Adds integration tests for recording and disabling customizations via the tool.
crates/jcode-selfdev-types/src/lib.rs Defines the durable customization record schema (status, provenance, validation, outcomes).
crates/jcode-selfdev-types/Cargo.toml Adds serde_json dev-dependency for schema tests.
crates/jcode-build-support/src/customizations.rs Adds on-disk storage helpers for records/patches plus record ID sanitization and outcome appends.
crates/jcode-build-support/src/source_state.rs Adds helper to build a patch including untracked files.
crates/jcode-build-support/src/lib.rs Re-exports customization APIs and new patch helper.
crates/jcode-build-support/src/tests.rs Adds round-trip, untracked patch, and outcome persistence tests.
Cargo.lock Locks new dev-dependency resolution.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/update.rs
Comment on lines +976 to +1012
fn run_customization_validation_commands(
repo_dir: &Path,
commands: &[String],
) -> (build::SelfDevCustomizationOutcomeStatus, String) {
let mut combined = String::new();
for command in commands {
let output = if cfg!(windows) {
std::process::Command::new("cmd")
.args(["/C", command])
.current_dir(repo_dir)
.output()
} else {
std::process::Command::new("sh")
.args(["-c", command])
.current_dir(repo_dir)
.output()
};

let output = match output {
Ok(output) => output,
Err(error) => {
return (
build::SelfDevCustomizationOutcomeStatus::ValidationFailed,
truncate_chars(
&format!("Validation command `{command}` failed to start: {error}"),
CUSTOMIZATION_VALIDATION_OUTPUT_LIMIT,
),
);
}
};

append_validation_output(&mut combined, command, &output);
if !output.status.success() {
return (
build::SelfDevCustomizationOutcomeStatus::ValidationFailed,
truncate_chars(&combined, CUSTOMIZATION_VALIDATION_OUTPUT_LIMIT),
);
Comment thread src/update.rs Outdated
Comment on lines +1022 to +1044
fn append_validation_output(combined: &mut String, command: &str, output: &std::process::Output) {
if !combined.is_empty() {
combined.push_str("\n\n");
}
combined.push_str(&format!(
"Command: `{}`\nStatus: {}\n",
command,
output.status.code().map_or_else(
|| "terminated by signal".to_string(),
|code| code.to_string()
)
));
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.trim().is_empty() {
combined.push_str("Stdout:\n");
combined.push_str(stdout.trim());
combined.push('\n');
}
let stderr = String::from_utf8_lossy(&output.stderr);
if !stderr.trim().is_empty() {
combined.push_str("Stderr:\n");
combined.push_str(stderr.trim());
combined.push('\n');
Comment thread src/update.rs Outdated
Comment on lines +906 to +907
let Ok(active) = build::list_active_customization_records() else {
return;
Comment on lines +194 to +196
pub fn current_git_patch_with_untracked(repo_dir: &Path) -> Result<String> {
let mut patch = current_git_diff(repo_dir)?;
let untracked = git_output_bytes(
let mut clean = String::with_capacity(id.len());
for ch in id.chars() {
if ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_') {
clean.push(ch);
Comment on lines +57 to +65
record.id = sanitize_record_id(&record.id);
let now = Utc::now();
record.updated_at = now;
if record.created_at > now {
record.created_at = now;
}

if let Some(patch) = patch.filter(|patch| !patch.trim().is_empty()) {
let patch_path = customization_patch_path(&record.id)?;
}

pub fn save_customization_record(record: &SelfDevCustomizationRecord) -> Result<()> {
storage::write_json(&customization_record_path(&record.id)?, record)
Comment thread src/tool/selfdev/customization.rs Outdated
let diff = if Self::is_test_session() {
String::new()
} else {
build::current_git_patch_with_untracked(&repo_dir).unwrap_or_default()
Comment on lines +109 to +111
if let Some(validation_status) = record.validation.last_status.as_ref() {
status.push_str(&format!(" Last validation: {:?}\n", validation_status));
}
@aayu22809
Copy link
Copy Markdown
Author

Reviewed Copilot suggestions and pushed follow-up commit 44f8361f.

Accepted/addressed:

  • Added warning log when active customization records cannot be loaded during update reporting.
  • Changed tracked patch capture to git diff --binary HEAD so tracked binary changes are represented consistently with untracked binary files.
  • Normalized sanitized record IDs to lowercase to avoid case-insensitive filesystem collisions.
  • Made record creation fail if the target record or patch path already exists instead of overwriting.
  • Switched customization record JSON writes to write_json_secret, matching patch privacy expectations.
  • Made patch capture failure fail record-customization instead of silently storing an empty patch.
  • Rendered validation status as stable snake_case labels in selfdev status.
  • Added per-command timeout and bounded stdout/stderr capture for validation commands. Timeouts are reported as validation failures and remain report-only.

Validated with:

cargo test -p jcode-build-support customization --lib
cargo test -p jcode-selfdev-types --lib
cargo test record_customization_creates_record_and_list_output --lib
cargo test disable_customization_removes_compact_memory_and_active_status --lib
cargo test test_record_customization_update_reports_validation_pass --lib
cargo test test_record_customization_update_reports_validation_failure_is_report_only --lib
cargo check

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants