Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion .claude/rules/00-deliberation.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,58 @@ Claude: "The crash is caused by X. Here are 3 approaches to fix it:
You are not here to "fix things quickly."
You are here to help make good engineering decisions.
Quick fixes create technical debt.
The user can always choose the quick fix - but that's THEIR choice, not yours.
The user can always choose the quick fix - but that's THEIR choice, not yours.

---

## NO LEGACY SUPPORT. EVER.

This is **GREENFIELD DEVELOPMENT**. There is NO legacy to support.

### ABSOLUTELY FORBIDDEN:

1. **Legacy wrappers** - NEVER wrap old code. Delete it.
2. **Backwards compatibility** - NEVER maintain old behavior. Replace it.
3. **Deprecation notices** - NEVER deprecate. Just remove.
4. **Migration code** - NEVER write migration paths. Just rewrite.
5. **Old API preservation** - NEVER keep old signatures "just in case". Delete them.
6. **Compatibility shims** - NEVER. EVER.

### THE ONLY ACCEPTABLE APPROACH:

**FULL REWRITES.**

If code needs to change, REWRITE IT. Don't patch it. Don't wrap it. Don't preserve the old way.

### Why This Matters:

Every legacy wrapper, every backwards-compatible hack, every deprecation notice is **technical debt**.
This is a new codebase. There are no users depending on old behavior.
There is NOTHING to be backwards compatible WITH.

### Example of What NOT to Do:

```rust
// BAD - Legacy wrapper
#[deprecated(note = "Use new_method instead")]
fn old_method() { new_method() }

// BAD - Backwards compatibility
fn process(data: Data, legacy_mode: bool) {
if legacy_mode { old_behavior() } else { new_behavior() }
}

// BAD - Keeping old code "just in case"
// fn old_implementation() { ... } // Commented out for reference
```

### The ONLY Acceptable Approach:

```rust
// GOOD - Just the new code. Old code is DELETED.
fn process(data: Data) {
new_behavior()
}
```

**DELETE THE OLD. WRITE THE NEW. NO BRIDGES.**
30 changes: 15 additions & 15 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,21 @@ jobs:
# Checks for known vulnerabilities in dependencies
# Only runs on main branch, PRs to main, and scheduled builds
# ============================================================
audit:
name: Security Audit
runs-on: ubuntu-latest
if: github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Install cargo-audit
uses: taiki-e/install-action@v2
with:
tool: cargo-audit

- name: Run security audit
run: cargo audit --deny warnings
# audit:
# name: Security Audit
# runs-on: ubuntu-latest
# if: github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
# steps:
# - name: Checkout repository
# uses: actions/checkout@v6
#
# - name: Install cargo-audit
# uses: taiki-e/install-action@v2
# with:
# tool: cargo-audit
#
# - name: Run security audit
# run: cargo audit --deny warnings

# ============================================================
# Security Analysis (SARIF)
Expand Down
2 changes: 1 addition & 1 deletion .zenodo.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "Trial Submission Studio",
"description": "Trial Submission Studio is an open-source desktop application that transforms clinical trial data into FDA-compliant CDISC formats. It provides multi-format output support (XPT V5/V8, Dataset-XML, Define-XML 2.1), intelligent fuzzy column matching with confidence scores, built-in CDISC Controlled Terminology validation, and cross-platform native applications for macOS, Windows, and Linux. All standards are embedded for offline use.",
"version": "0.0.4-alpha",
"version": "0.0.5-alpha",
"upload_type": "software",
"access_right": "open",
"license": "mit",
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ keywords:
- desktop-application
- cross-platform
license: MIT
version: '0.0.4-alpha'
date-released: '2026-01-24'
version: '0.0.5-alpha'
date-released: '2026-01-25'
19 changes: 18 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ For feature development, ALWAYS start with `/feature-dev` to gather requirements
Trial Submission Studio transforms clinical trial source data (CSV) into FDA-compliant CDISC formats (SDTM, ADaM, SEND).
It's a cross-platform desktop application written in Rust using the Iced GUI framework.

**Status**: Alpha software (v0.0.4-alpha). Not for production regulatory submissions.
**Status**: Alpha software (v0.0.5-alpha). Not for production regulatory submissions.

---

Expand Down Expand Up @@ -205,6 +205,23 @@ Project files use `.tss` format:

This is **greenfield development** - we are building a new desktop application with no legacy constraints.

### NO LEGACY SUPPORT. EVER.

**ABSOLUTELY FORBIDDEN:**

- **Legacy wrappers** - NEVER wrap old code. Delete it.
- **Backwards compatibility** - NEVER maintain old behavior. Replace it.
- **Deprecation notices** - NEVER deprecate. Just remove.
- **Migration code** - NEVER write migration paths. Just rewrite.
- **Old API preservation** - NEVER keep old signatures "just in case". Delete them.
- **Compatibility shims** - NEVER. EVER.
- **Commented-out old code** - NEVER keep "for reference". Delete it.

**THE ONLY ACCEPTABLE APPROACH: FULL REWRITES.**

There are NO users depending on old behavior. There is NOTHING to be backwards compatible WITH.
If code needs to change, REWRITE IT. Don't patch. Don't wrap. Don't preserve.

### Key Principles

- **No backwards compatibility needed** - break anything that improves the codebase
Expand Down
25 changes: 18 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ members = [
resolver = "3"

[workspace.package]
version = "0.0.4-alpha"
version = "0.0.5-alpha"
edition = "2024"
rust-version = "1.92"
license = "MIT"
Expand All @@ -21,6 +21,7 @@ exclude = ["resources/"]

[workspace.dependencies]
anyhow = "1.0"
encoding_rs = "0.8"
chrono = { version = "0.4", features = ["serde"] }
csv = "1.4.0"
futures-util = "0.3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<content_rating type="oars-1.1"/>

<releases>
<release version="0.0.4-alpha" date="2026-01-24">
<release version="0.0.5-alpha" date="2026-01-25">
<description>
<p>Alpha release with core SDTM transformation features:</p>
<ul>
Expand Down
6 changes: 3 additions & 3 deletions codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"@id": "https://doi.org/10.5281/zenodo.18148150",
"name": "Trial Submission Studio",
"description": "Trial Submission Studio is an open-source desktop application that transforms clinical trial data into FDA-compliant CDISC formats. It provides multi-format output support (XPT V5/V8, Dataset-XML, Define-XML 2.1), intelligent fuzzy column matching with confidence scores, built-in CDISC Controlled Terminology validation, and cross-platform native applications for macOS, Windows, and Linux. All standards are embedded for offline use.",
"version": "0.0.4-alpha",
"version": "0.0.5-alpha",
"identifier": [
{
"@type": "PropertyValue",
Expand Down Expand Up @@ -47,13 +47,13 @@
"continuousIntegration": "https://github.com/rubentalstra/trial-submission-studio/actions",
"issueTracker": "https://github.com/rubentalstra/trial-submission-studio/issues",
"dateCreated": "2025-12-12",
"dateModified": "2026-01-24",
"dateModified": "2026-01-25",
"datePublished": "2026-01-05",
"programmingLanguage": [
{
"@type": "ComputerLanguage",
"name": "Rust",
"version": "0.0.4-alpha",
"version": "0.0.5-alpha",
"url": "https://www.rust-lang.org/"
}
],
Expand Down
57 changes: 5 additions & 52 deletions crates/tss-gui/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

// Submodules - handlers are organized by category in handler/
mod handler;
mod subscription;
pub mod util;

// Re-export utility functions for internal use
use util::load_app_icon;

use iced::keyboard;
use iced::widget::container;
use iced::window;
use iced::{Element, Size, Subscription, Task, Theme};
Expand Down Expand Up @@ -680,58 +680,11 @@ impl App {
}

/// Subscribe to runtime events.
///
/// Delegates to `subscription::create_subscription` which manages all
/// application subscriptions in a centralized module.
pub fn subscription(&self) -> Subscription<Message> {
use iced::{system, time};
use std::time::Duration;

// Keyboard events
let keyboard_sub = keyboard::listen().map(|event| match event {
keyboard::Event::KeyPressed { key, modifiers, .. } => {
Message::KeyPressed(key, modifiers)
}
_ => Message::Noop,
});

// System theme changes (for ThemeMode::System)
let system_theme_sub = system::theme_changes().map(Message::SystemThemeChanged);

// Native menu event polling (macOS only, polls every 50ms for responsiveness)
#[cfg(target_os = "macos")]
let menu_sub = crate::menu::menu_subscription().map(|action| match action {
Some(a) => Message::MenuAction(a),
None => Message::Noop,
});

#[cfg(not(target_os = "macos"))]
let menu_sub = Subscription::none();

// Window close events (for cleaning up dialog windows)
let window_sub = window::close_requests().map(Message::DialogWindowClosed);

// Toast auto-dismiss timer (5 seconds)
let toast_sub = if self.state.toast.is_some() {
time::every(Duration::from_secs(5))
.map(|_| Message::Toast(crate::message::ToastMessage::Dismiss))
} else {
Subscription::none()
};

// Auto-save timer (polls every 500ms to check if auto-save should trigger)
// The actual save only happens if the dirty tracker indicates it should
let auto_save_sub = if self.state.auto_save_config.enabled && self.state.study.is_some() {
time::every(Duration::from_millis(500)).map(|_| Message::AutoSaveTick)
} else {
Subscription::none()
};

Subscription::batch([
keyboard_sub,
system_theme_sub,
menu_sub,
window_sub,
toast_sub,
auto_save_sub,
])
subscription::create_subscription(&self.state)
}
}

Expand Down
Loading