Project: Impulse-Next_BBS (Impulse 7.1 BBS Modernization) Date: 2025-11-23 Version: 1.0 Status: Sprint 3 Complete - Ready for Implementation
- Executive Summary
- Strategic Principles
- Risk-Based Prioritization Framework
- Platform-Specific Migration Strategy
- 4-Phase Conversion Roadmap
- Type System Migration Strategy
- Global State Refactoring Strategy
- Binary File Format Strategy
- Dependency Management Strategy
- Testing Strategy
- High-Risk Module Strategy
- Sprint Execution Guidelines
- Success Metrics & KPIs
- Risk Mitigation Timeline
- Parallel Conversion Opportunities
- Cross-References
This document provides a comprehensive strategy for converting the Impulse 7.1 BBS system from Borland Pascal 7.0 to Rust 2024 edition. The conversion encompasses 114 Pascal units (39,079 lines of code) with 1,070 dependencies, transforming a DOS-era bulletin board system into a modern, cross-platform application.
Source Files: Based on comprehensive analysis documented in ../pascal-reference/:
- pascal-inventory.md - Complete unit inventory
- pascal-unit-analysis.md - Detailed unit analysis
- pascal-dependencies.md - Dependency documentation
- conversion-risk-assessment.md - Risk ratings
- conversion-order.md - Priority order
- 13 additional analysis documents
| Metric | Value | Source |
|---|---|---|
| Total Pascal Units | 114 | pascal-inventory.md |
| Total Lines of Code | 39,079 | pascal-inventory.md |
| Total Dependencies | 1,070 | pascal-dependencies.md |
| Average Dependencies/Unit | 9.4 | pascal-dependencies.md |
| CRITICAL Risk Units | 11 (9.6%) | conversion-risk-assessment.md |
| HIGH Risk Units | 27 (23.7%) | conversion-risk-assessment.md |
| MEDIUM Risk Units | 30 (26.3%) | conversion-risk-assessment.md |
| LOW Risk Units | 46 (40.4%) | conversion-risk-assessment.md |
| Category | Count | Files | Source |
|---|---|---|---|
| DOS Function Calls | 23 files | EXEC, GETDIR, MKDIR, CHDIR, RMDIR, SWAPVECTORS, KEEP | pascal-dos-specific.md |
| Overlay Directives | 75 directives | IMP.PAS (74), TIMETASK.PAS (1) | pascal-overlays.md |
| Interrupt Handlers | 2 files | TMPCOM.PAS (48), TMPOLD.PAS (48) | pascal-interrupts.md |
| Inline Assembly | 14 files | NETFOSSL.PAS (26), MYIO.PAS (8), others | pascal-interrupts.md |
| ABSOLUTE Variables | 2 files | MAIL7.PAS (2), ZIPVIEWU.PAS (1) | pascal-interrupts.md |
| Binary File I/O | 29 files | FILE OF RecordType pattern | pascal-binary-formats.md |
| Global Variables | 90 files | Mutable state in INTERFACE section | pascal-globals.md |
Total Duration: 24 months (Sprints 3-32)
| Phase | Sprints | Duration | Units | Focus |
|---|---|---|---|---|
| Phase 1 | 3-10 | Months 1-4 | 28 | Foundation (core types, utilities) |
| Phase 2 | 11-18 | Months 5-10 | 28 | Core Services (files, mail, users) |
| Phase 3 | 19-26 | Months 11-18 | 28 | Advanced Features (sysop, protocols) |
| Phase 4 | 27-32 | Months 19-24 | 30 | Integration (main program, high-risk) |
Source: conversion-order.md
- Dependency-Aware Conversion - Convert foundation modules (RECORDS.PAS, COMMON*.PAS) first
- Binary Compatibility - Maintain compatibility with existing BBS data files or provide migration tools
- Risk Mitigation - Address high-risk modules (33.3% of codebase) with expert review and extensive testing
- Parallel Conversion - Exploit module independence to parallelize work (estimated 30-40% time reduction)
- Continuous Testing - Test each converted module against original Pascal behavior
The conversion strategy is built on six core principles that guide all technical decisions:
Principle: Maintain 100% functional compatibility with Impulse 7.1 while modernizing the underlying architecture.
Application:
- Convert business logic faithfully (same algorithms, same behavior)
- Modernize platform dependencies (DOS→cross-platform)
- Improve error handling (Pascal→Result<T, E>)
- Add safety (global state→owned/borrowed types)
Example:
// Pascal: procedure ProcessUpload(var f: ulfrec);
// Rust: fn process_upload(file_entry: &mut FileEntry) -> Result<(), BbsError>Source: type-mapping.md
Principle: Leverage Rust's safety guarantees without compromising performance or functionality.
Application:
- Replace unsafe pointer manipulation with safe references
- Use
Option<T>instead of nullable pointers - Eliminate global mutable state where possible
- Maintain binary compatibility where necessary (bincode serialization)
Trade-offs:
- Some performance overhead for safety (acceptable for BBS workloads)
- Increased code verbosity (Result types, error handling)
- Stricter type requirements (worth the compile-time guarantees)
Source: pascal-globals.md
Principle: Convert modules in dependency order to minimize rework and integration issues.
Application:
- Foundation First: RECORDS.PAS (core types) must be converted before dependent modules
- Leaf Nodes Last: Modules with many dependencies (IMP.PAS with 69 deps) converted late
- Common Utilities Early: COMMON*.PAS modules converted in Phase 1 (high dependency impact)
Priority Formula:
priority_score = (risk_score * 10) + (dependency_count * 2) - (dependency_impact * 5)
Lower score = Higher priority (convert earlier)
Source: conversion-order.md
Principle: Allocate senior developers and extra time to high-risk modules (33.3% of codebase).
Risk Categories:
| Risk Level | Count | Percentage | Strategy |
|---|---|---|---|
| CRITICAL | 11 | 9.6% | Senior dev + pair programming + extensive testing |
| HIGH | 27 | 23.7% | Senior dev + peer review + integration tests |
| MEDIUM | 30 | 26.3% | Standard process + unit tests |
| LOW | 46 | 40.4% | Junior/mid-level dev + basic tests |
Source: conversion-risk-assessment.md
Principle: Write tests before converting modules to ensure behavioral equivalence.
Application:
- Pre-Conversion: Characterization tests using Pascal original as oracle
- During Conversion: Unit tests for each converted function
- Post-Conversion: Integration tests for module interactions
- Binary Compatibility: Round-trip tests (write with Rust, read with Pascal, and vice versa)
Test Coverage Targets:
- Critical risk modules: 95%+ coverage
- High risk modules: 85%+ coverage
- Medium risk modules: 75%+ coverage
- Low risk modules: 60%+ coverage
Source: SPRINT-03-COMPLETION-REPORT.md
Principle: Design for Linux, Windows, and macOS from the first line of code.
Application:
- Abstract platform-specific calls behind traits
- Use
std::process::Commandinstead of DOS Exec - Replace interrupts with OS-specific signal handlers
- Test on all three platforms in CI pipeline
Platform Abstraction Example:
trait FileSystemOps {
fn current_dir() -> Result<PathBuf, std::io::Error>;
fn create_dir(&self, path: &Path) -> Result<(), std::io::Error>;
fn change_dir(&self, path: &Path) -> Result<(), std::io::Error>;
}
// DOS: GETDIR, MKDIR, CHDIR → Rust: std::env, std::fsSource: pascal-dos-specific.md
The conversion risk assessment uses a quantitative scoring system to identify modules requiring special attention.
Source: conversion-risk-assessment.md
- Interrupt Handlers - Platform-specific, no modern equivalent
- ABSOLUTE Variables - Direct memory access, hardware I/O
- Low-level DOS Interrupts - SwapVectors, GetInterVec, SetInterVec
Affected Modules:
- TMPCOM.PAS, TMPOLD.PAS (interrupt handlers)
- MAIL7.PAS, ZIPVIEWU.PAS (ABSOLUTE variables)
- EXEC.PAS, EXECOLD.PAS, RECORDS.PAS, COMMON5.PAS, SCRIPT.PAS, INSTALL.PAS, BPTRAP.PAS, SYSOP2D.PAS (DOS interrupts)
- Inline Assembly - CPU-specific, may need intrinsics or pure Rust
- Process Execution - DOS Exec requires std::process::Command
Affected Modules: 14 files with inline assembly (NETFOSSL.PAS, MYIO.PAS, ANSIDRV.PAS, etc.)
- Overlay System Usage - DOS memory management, remove directives
- Binary File I/O - Maintain compatibility with existing data
Affected Modules: 29 files with binary I/O, 2 files with overlays
- DOS File System Calls - GETDIR, MKDIR, CHDIR, RMDIR
- Heavy Pointer Usage - Manual memory management (>50 occurrences)
- Variant Records - Pascal unions → Rust enums
- Module Size - >500 lines
- Dependency Count - >10 dependencies
| Level | Score Range | Count | Strategy |
|---|---|---|---|
| CRITICAL | ≥ 20 | 11 | Expert team, extensive testing, phased conversion |
| HIGH | 10-19 | 27 | Senior developer, peer review, integration tests |
| MEDIUM | 5-9 | 30 | Standard process, unit tests |
| LOW | < 5 | 46 | Straightforward conversion, basic tests |
Source: high-risk-units.md
| Rank | Module | Risk Score | Risk Level | Key Challenges | Dependencies |
|---|---|---|---|---|---|
| 1 | EXEC.PAS | 31 | CRITICAL | DOS interrupts, assembly, Exec, pointers, 974 lines | 2 |
| 2 | EXECOLD.PAS | 31 | CRITICAL | DOS interrupts, assembly, Exec, pointers, 974 lines | 2 |
| 3 | RECORDS.PAS | 28 | CRITICAL | DOS interrupts, assembly, Exec, 830 lines, CORE TYPES | 0 |
| 4 | COMMON.PAS | 27 | CRITICAL | Assembly, Exec, binary I/O, 107 pointers, 1960 lines | 5 |
| 5 | COMMON5.PAS | 27 | CRITICAL | DOS interrupts, assembly, Exec | 1 |
| 6 | INSTALL.PAS | 25 | CRITICAL | DOS interrupts, Exec, binary I/O, file system | 3 |
| 7 | SCRIPT.PAS | 24 | CRITICAL | DOS interrupts, Exec, file system, 951 lines | 10 |
| 8 | IMP.PAS | 22 | CRITICAL | Exec, overlays, binary I/O, file system, 69 deps | 69 |
| 9 | MAIL7.PAS | 22 | CRITICAL | ABSOLUTE vars, Exec, 517 lines, 15 deps | 15 |
| 10 | BPTRAP.PAS | 21 | CRITICAL | DOS interrupts, assembly, 11 deps | 11 |
Critical Insight: RECORDS.PAS (rank 3) has zero dependencies and defines all core types - it must be converted first despite CRITICAL risk level.
The original Impulse 7.1 BBS was built for DOS, requiring extensive platform-specific code modernization.
Source: pascal-dos-specific.md, pascal-interrupts.md
| DOS Function | Count | Rust Replacement | Strategy |
|---|---|---|---|
| EXEC | 23 files | std::process::Command |
Spawn processes, handle I/O with pipes |
| GETDIR | 16 files | std::env::current_dir() |
Direct replacement |
| MKDIR | 7 files | std::fs::create_dir() |
Direct replacement |
| CHDIR | 12 files | std::env::set_current_dir() |
Direct replacement |
| RMDIR | 4 files | std::fs::remove_dir() |
Direct replacement |
| SWAPVECTORS | 6 files | N/A (DOS-specific) | Remove, not needed in modern OS |
| KEEP | 3 files | N/A (TSR functionality) | Remove, not applicable |
Implementation Example:
// Pascal: Exec(GetEnv('COMSPEC'), '/C ' + command);
// Rust:
use std::process::Command;
fn execute_shell_command(command: &str) -> Result<(), BbsError> {
let shell = std::env::var("COMSPEC")
.or_else(|_| std::env::var("SHELL"))
.unwrap_or_else(|_| "/bin/sh".to_string());
let output = Command::new(shell)
.arg("-c")
.arg(command)
.output()?;
if !output.status.success() {
return Err(BbsError::CommandFailed(output.stderr));
}
Ok(())
}Challenge: 2 files (TMPCOM.PAS, TMPOLD.PAS) use DOS interrupt handlers (48 each) for serial port communication.
Modern Solution: Replace with OS-specific signal handlers or serial port libraries.
// Unix/Linux
use signal_hook::{consts::SIGINT, iterator::Signals};
fn setup_signal_handlers() -> Result<(), std::io::Error> {
let mut signals = Signals::new(&[SIGINT])?;
std::thread::spawn(move || {
for signal in signals.forever() {
match signal {
SIGINT => handle_interrupt(),
_ => {},
}
}
});
Ok(())
}
// Windows
#[cfg(target_os = "windows")]
use winapi::um::consoleapi::SetConsoleCtrlHandler;Source: risk-mitigations.md
Challenge: 14 files use inline assembly for:
- CPU feature detection
- Direct hardware I/O
- Performance-critical operations
Strategy:
- Evaluate Necessity - Often Rust has better alternatives
- Use std::arch - For CPU intrinsics (SIMD, etc.)
- Use asm! macro - For unavoidable assembly
- Abstract Behind Safe Interface - Isolate unsafe blocks
use std::arch::x86_64::*;
// Safe wrapper around assembly
fn cpu_feature_check() -> bool {
unsafe { is_x86_feature_detected!("sse2") }
}
// If asm! is absolutely necessary
#[cfg(target_arch = "x86_64")]
unsafe fn low_level_operation() {
asm!(
"mov {0}, rax",
out(reg) _,
options(nostack, preserves_flags)
);
}Source: risk-mitigations.md
Challenge: 75 overlay directives in 2 files (IMP.PAS: 74, TIMETASK.PAS: 1)
Solution: Simply remove overlay directives - modern OS handles memory paging automatically.
Pascal:
{$O MAIL0}
{$O MAIL1}
{$O MAIL2}Rust:
// No equivalent needed - standard module system
mod mail0;
mod mail1;
mod mail2;Source: pascal-overlays.md
Challenge: 2 files (MAIL7.PAS, ZIPVIEWU.PAS) use ABSOLUTE variables for memory-mapped I/O.
Solution: Replace with OS-specific memory mapping APIs.
// Unix: mmap, Windows: MapViewOfFile
use memmap2::MmapMut;
fn map_hardware_memory(address: usize, size: usize) -> Result<MmapMut, std::io::Error> {
// Platform-specific implementation
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open("/dev/mem")?;
unsafe { MmapMut::map_mut(file.as_raw_fd()) }
}
#[cfg(windows)]
{
// Windows-specific memory mapping
unimplemented!("Windows memory mapping not yet implemented")
}
}Source: high-risk-units.md
The conversion is organized into 4 phases across 30 sprints (Sprints 3-32), with each phase building upon the previous.
Source: conversion-order.md
Goal: Establish core types, utilities, and infrastructure for subsequent phases.
Duration: 8 sprints (~3 weeks each)
Units to Convert: 28 units (24.6% of codebase)
| Priority | Module | Risk Level | Dependencies | Rationale |
|---|---|---|---|---|
| 1 | STRPROC | LOW | 0 | High dependency impact (88), zero deps |
| 2 | TIMEJUNK | LOW | 1 | High dependency impact (87) |
| 3 | SCRLBK | LOW | 3 | High dependency impact (86) |
| 14 | RECORDS | CRITICAL | 0 | MUST BE FIRST - Core types, 93 deps on it |
| 15 | COMMON5 | CRITICAL | 1 | High dependency impact (88) |
| 18 | COMMON | CRITICAL | 5 | High dependency impact (86), 1960 lines |
| 10 | COMMON1 | HIGH | 5 | Common utilities |
| 12 | COMMON2 | HIGH | 11 | Common utilities |
Sprint Breakdown:
- Sprint 3: Pascal Analysis (COMPLETE)
- Sprint 4: Configuration System (
impulse-configcrate) - Sprint 5: Core Types Implementation (RECORDS.PAS → Rust)
- Convert all record types
- Implement bincode serialization
- Binary compatibility validation
- Sprint 6-7: Common Utilities (COMMON*.PAS modules)
- STRPROC, TIMEJUNK, SCRLBK (low risk)
- COMMON5, COMMON, COMMON1, COMMON2 (critical/high risk)
- Sprint 8-9: Binary File I/O and Serialization
- Implement binary file reading/writing
- Test with existing BBS data files
- Create migration tools if needed
- Sprint 10: Phase 1 Integration and Testing
- Integration tests for all Phase 1 modules
- Performance benchmarking
- Documentation updates
Success Criteria:
- ✅ All core types implemented and tested
- ✅ Common utilities passing tests (100% for CRITICAL modules)
- ✅ Binary file I/O working for at least one record type
- ✅ Serialization round-trip tests passing
- ✅ Foundation ready for Phase 2 (file/mail modules)
Goal: Build functional BBS core - file areas, message system, user management.
Duration: 8 sprints
Units to Convert: 28 units (24.6% of codebase)
| Module Group | Count | Risk Distribution | Focus |
|---|---|---|---|
| FILE* | 14 | 5 HIGH, 4 MEDIUM, 5 LOW | File area management, uploads/downloads |
| MAIL* | 9 | 1 CRITICAL, 1 HIGH, 3 MEDIUM, 4 LOW | Message base, email, networking |
| MISC* | 5 | 1 HIGH, 3 MEDIUM, 1 LOW | Miscellaneous utilities |
| Other | - | - | User auth, session management |
Sprint Breakdown:
- Sprints 11-13: File Management Modules
- FILE0-FILE14 (file areas, upload/download)
- File listing, searching, batch operations
- Sprints 14-16: User and Message System
- MAIL0-MAIL9 (message base, email)
- User authentication (CUSER, NEWUSERS)
- Session management
- Sprint 17: Authentication and Sessions
- Argon2 password hashing
- Session tokens and timeouts
- Multi-user support
- Sprint 18: Phase 2 Integration and Testing
- Integration tests for file/mail/user modules
- End-to-end testing (user login → file upload → message post)
- Performance optimization
Success Criteria:
- ✅ File upload/download operational
- ✅ Message base working (create, read, reply)
- ✅ User authentication functional
- ✅ Session state management tested
- ✅ Binary compatibility with Impulse 7.1 data files verified
Goal: System operator functions, networking, protocol handlers, terminal emulation.
Duration: 8 sprints
Units to Convert: 28 units (24.6% of codebase)
| Module Group | Count | Risk Distribution | Focus |
|---|---|---|---|
| SYSOP* | 22 | 4 HIGH, 6 MEDIUM, 12 LOW | System operator menus and functions |
| Protocols | - | - | Telnet (RFC 854, 857, 858, 1073), SSH (RFC 4253, 4254) |
| Terminal | - | - | ANSI, Avatar, RIP emulation |
| Doors | - | - | Door game interface, dropfiles, FOSSIL |
Sprint Breakdown:
- Sprints 19-21: System Operator Functions
- SYSOP1-SYSOP11, SYSOP2* modules
- User management, file management, system config
- Sprints 22-23: Protocol Handlers
- Telnet server (
impulse-telnetcrate) - SSH server (
impulse-sshcrate) - Protocol abstraction layer
- Telnet server (
- Sprint 24-25: Terminal Emulation and Door Games
- ANSI/Avatar/RIP emulation (
impulse-terminalcrate) - Door game interface (
impulse-doorcrate) - Dropfile generation (DOOR.SYS, DORINFO*.DEF)
- ANSI/Avatar/RIP emulation (
- Sprint 26: Phase 3 Integration and Testing
- Integration tests for all Phase 3 modules
- Multi-protocol testing (Telnet + SSH simultaneously)
- Terminal emulation compatibility testing
Success Criteria:
- ✅ SysOp menu functional
- ✅ Message networking operational
- ✅ Telnet connections working
- ✅ SSH connections working
- ✅ ANSI terminal emulation tested
- ✅ Door game interface tested (at least one door game working)
Goal: Complete system integration, high-risk modules, final testing, deployment.
Duration: 6 sprints
Units to Convert: 30 units (26.3% of codebase, includes highest-risk modules)
| Module | Risk Score | Risk Level | Rationale |
|---|---|---|---|
| IMP.PAS | 22 | CRITICAL | Main program, 69 dependencies, overlay system |
| EXEC.PAS | 31 | CRITICAL | Process execution, DOS interrupts, assembly |
| EXECOLD.PAS | 31 | CRITICAL | Legacy process execution |
| INSTALL.PAS | 25 | CRITICAL | Installation program |
| IMPDOS.PAS | 20 | CRITICAL | DOS-specific operations |
| MAIL7.PAS | 22 | CRITICAL | ABSOLUTE variables |
| SCRIPT.PAS | 24 | CRITICAL | Script execution |
| MENUS.PAS | 13 | HIGH | Menu system, 62 dependencies |
| WFCMENU.PAS | 19 | HIGH | Wait for caller menu, 33 dependencies |
Sprint Breakdown:
- Sprint 27-28: Main Program and High-Risk Modules
- IMP.PAS → impulse-server binary
- EXEC/EXECOLD → process execution abstraction
- SCRIPT → script interpreter
- Sprint 29: Full System Integration
- All crates integrated into workspace
- End-to-end testing (complete BBS operation)
- Migration tools for existing BBS data
- Sprint 30: Cross-Platform Testing
- Linux (primary target)
- Windows 11 (secondary target)
- macOS (tertiary target)
- CI/CD pipeline verification
- Sprint 31: Performance Optimization
- Profiling (flamegraphs, perf)
- Hotspot optimization
- Memory usage reduction
- Concurrency improvements (Tokio)
- Sprint 32: Documentation and Release Preparation
- User documentation (installation, operation, migration)
- Developer documentation (architecture, contributing)
- Release notes and changelog
- v1.0 release candidate
Success Criteria:
- ✅ Complete BBS operational (all features working)
- ✅ All 114 modules converted and tested
- ✅ Verified on Linux, Windows 11, and macOS
- ✅ Performance benchmarks met (latency < 100ms for typical operations)
- ✅ Migration tools tested with real Impulse 7.1 BBS data
- ✅ v1.0 release candidate ready for deployment
The Pascal type system differs significantly from Rust, requiring careful mapping to preserve functionality while gaining safety.
Source: type-mapping.md
| Pascal Type | Size | Range | Rust Type | Migration Notes |
|---|---|---|---|---|
Byte |
1 byte | 0..255 | u8 |
Direct mapping |
ShortInt |
1 byte | -128..127 | i8 |
Direct mapping |
Word |
2 bytes | 0..65535 | u16 |
Direct mapping |
Integer |
2 bytes | -32768..32767 | i16 |
Most common integer type |
LongInt |
4 bytes | -2³¹..2³¹-1 | i32 |
Direct mapping |
Cardinal |
4 bytes | 0..2³²-1 | u32 |
Direct mapping |
Comp |
8 bytes | Large integer | i64 |
Rare in codebase |
Critical Insight: Pascal Integer is 16-bit, while Rust i32 is the default. Use i16 for Pascal Integer to avoid overflow issues.
| Pascal Type | Rust Type | Migration Strategy |
|---|---|---|
String[N] (fixed-length) |
String or [u8; N] |
Dynamic String for flexibility, fixed array for binary compatibility |
String (ShortString, max 255) |
String |
Direct mapping to dynamic string |
PChar (null-terminated) |
&str or CString |
Use &str for text, CString for C interop |
AnsiString (dynamic) |
String |
Direct mapping |
Binary Compatibility Concern: For binary file I/O, use [u8; N] to match Pascal's fixed-length string layout:
#[derive(Serialize, Deserialize)]
struct UserRecord {
// Pascal: name: String[80];
name: [u8; 80], // Fixed-length for binary compatibility
name_len: u8, // Length byte (Pascal string format)
}
impl UserRecord {
fn name_as_str(&self) -> &str {
let len = self.name_len as usize;
std::str::from_utf8(&self.name[..len]).unwrap_or("")
}
}| Pascal Type | Rust Type | Use Case |
|---|---|---|
^Type (pointer) |
Box<Type> |
Heap-allocated, owned |
^Type |
&Type or &mut Type |
Borrowed reference (prefer this) |
^Type |
Arc<Type> |
Shared ownership, thread-safe |
^Type |
Rc<Type> |
Shared ownership, single-threaded |
nil |
None |
Use Option<T> for nullable pointers |
Migration Pattern:
// Pascal: if ptr <> nil then ptr^.field := value;
// Rust:
if let Some(ref mut data) = ptr_opt {
data.field = value;
}Heavy Pointer Usage: 8 modules have >50 pointer occurrences (COMMON: 107, MAIL1: 139, COMMON1: 85, ANSIEDIT: 66, COMMON2: 62, SYSOP3: 59, INITP: 57, WFCMENU: 55). These require careful refactoring to safe Rust patterns.
Pascal Record maps directly to Rust struct:
// Pascal:
// type
// UserRecord = record
// name: String[80];
// age: Integer;
// active: Boolean;
// end;
// Rust:
#[derive(Debug, Clone, Serialize, Deserialize)]
struct UserRecord {
name: String, // or [u8; 80] for binary compatibility
age: i16, // Pascal Integer = i16
active: bool,
}Variant Records (Pascal case...of) → Rust enums with data:
// Pascal:
// type
// ShapeType = (Circle, Rectangle);
// Shape = record
// case kind: ShapeType of
// Circle: (radius: Real);
// Rectangle: (width, height: Real);
// end;
// Rust:
#[derive(Debug, Clone)]
enum Shape {
Circle { radius: f32 },
Rectangle { width: f32, height: f32 },
}Pascal Set of types require Rust collections or bitflags:
| Pascal Set | Rust Type | Use Case |
|---|---|---|
Set of Enum |
HashSet<Enum> |
General purpose, dynamic membership |
Set of Byte |
BitVec or [bool; 256] |
Small sets, efficient storage |
Set of Char |
HashSet<char> |
Character sets |
| Flag sets | bitflags! macro |
Efficient flag storage |
Example:
// Pascal:
// type
// Flags = (fRead, fWrite, fExec);
// FlagSet = Set of Flags;
// Rust (bitflags):
use bitflags::bitflags;
bitflags! {
struct FlagSet: u8 {
const READ = 0b001;
const WRITE = 0b010;
const EXEC = 0b100;
}
}| Pascal Type | Rust Type | Strategy |
|---|---|---|
Text |
std::fs::File + BufReader/Writer |
Text file I/O |
File of Type |
std::fs::File + bincode |
Binary file I/O with serialization |
File (untyped) |
std::fs::File |
Raw file access |
Critical: 29 files use File of RecordType for binary I/O. See Section 8: Binary File Format Strategy for detailed migration.
The original Pascal codebase uses extensive global mutable state, which conflicts with Rust's ownership model and thread-safety guarantees.
Source: pascal-globals.md
Scope:
- 33 files export global constants (safe, map to
constorstatic) - 90 files export global mutable variables (problematic, need refactoring)
Categories of Global State:
- Session State - Current user, connection info, session timeout
- Configuration - BBS configuration, system paths
- File Handles - Open files (USER.LST, BOARDS.DAT, etc.)
- Caches - User cache, board cache, file area cache
- Flags - System flags, feature toggles
Example Global Variables (COMMON.PAS):
VAR
uf: file of userrec; { USER.LST }
bf: file of boardrec; { BOARDS.DAT }
sf: file of smalrec; { NAMES.LST }
thisuser: userrec; { current user }
systat: configrec; { system configuration }Encapsulate all global state in a single struct passed as parameter or stored in async context.
struct BbsState {
// Configuration
config: BbsConfig,
// Session state
current_user: Option<User>,
session_start: std::time::Instant,
// File handles (use Arc<Mutex<T>> for shared mutable access)
user_db: Arc<Mutex<UserDatabase>>,
board_db: Arc<Mutex<BoardDatabase>>,
// Caches
user_cache: Arc<RwLock<HashMap<UserId, User>>>,
// Flags
system_flags: Arc<RwLock<SystemFlags>>,
}
impl BbsState {
fn new(config: BbsConfig) -> Self {
Self {
config,
current_user: None,
session_start: std::time::Instant::now(),
user_db: Arc::new(Mutex::new(UserDatabase::open("data/users.dat")?)),
board_db: Arc::new(Mutex::new(BoardDatabase::open("data/boards.dat")?)),
user_cache: Arc::new(RwLock::new(HashMap::new())),
system_flags: Arc::new(RwLock::new(SystemFlags::default())),
}
}
}
// Usage in async context (Tokio)
tokio::task_local! {
static BBS_STATE: Arc<BbsState>;
}For single-threaded or thread-per-connection models:
use std::cell::RefCell;
thread_local! {
static BBS_STATE: RefCell<BbsState> = RefCell::new(BbsState::new());
}
fn get_current_user() -> Option<User> {
BBS_STATE.with(|state| state.borrow().current_user.clone())
}For truly global state accessed from multiple threads:
use std::sync::Mutex;
use once_cell::sync::Lazy;
static BBS_STATE: Lazy<Mutex<BbsState>> = Lazy::new(|| {
Mutex::new(BbsState::new())
});
fn get_current_user() -> Option<User> {
BBS_STATE.lock().unwrap().current_user.clone()
}Primary: BbsState struct with Tokio task-local storage (Option 1)
Rationale:
- Async-friendly (Tokio-based architecture)
- Per-connection state isolation
- Thread-safe with Arc/Mutex/RwLock
- Explicit state passing (better for testing)
Migration Steps:
- Sprint 5: Define BbsState struct with core fields
- Sprint 6-7: Refactor COMMON*.PAS to use BbsState
- Sprint 11-18: Extend BbsState for file/mail modules
- Sprint 19-26: Add protocol-specific state (Telnet, SSH)
- Sprint 27-32: Final integration and optimization
The original Impulse 7.1 BBS stores data in binary files using Pascal's File of RecordType pattern. Maintaining compatibility is critical for migration of existing BBS systems.
Source: pascal-binary-formats.md
Total: 29 files use binary file I/O
Critical Data Files:
| File | Record Type | Purpose | Estimated Size |
|---|---|---|---|
USER.LST |
userrec |
User accounts and statistics | ~1KB per user |
BOARDS.DAT |
boardrec |
Message board configuration | ~512B per board |
*.DIR |
ulfrec |
File area listings | ~512B per file |
MESSAGES.DAT |
messagerec |
Message headers | ~256B per message |
CONFIG.DAT |
configrec |
System configuration | ~10KB |
PROTOCOL.DAT |
protrec |
Protocol definitions | ~256B per protocol |
UPLOADS.DAT |
ulrec |
Upload tracking | ~256B per upload |
Use the bincode crate for binary serialization with serde derive macros.
Advantages:
- Binary format (compact, fast)
- Versioning support (can add version field)
- Compatible with Pascal record layout (with proper configuration)
- Easy migration path (can read old format, write new format)
Implementation:
use serde::{Serialize, Deserialize};
use bincode;
#[derive(Serialize, Deserialize, Debug, Clone)]
struct UserRecord {
// Match Pascal record layout exactly
name: [u8; 80], // String[80] in Pascal
password: [u8; 20], // String[20] in Pascal (NEVER store plaintext!)
age: i16, // Integer in Pascal
// ... other fields matching Pascal layout
}
// Reading legacy Pascal format
fn read_legacy_user(file: &mut File) -> Result<UserRecord, BbsError> {
let mut buffer = vec![0u8; std::mem::size_of::<UserRecord>()];
file.read_exact(&mut buffer)?;
Ok(bincode::deserialize(&buffer)?)
}
// Writing new format (with versioning)
#[derive(Serialize, Deserialize)]
struct UserRecordV2 {
version: u32, // Always 2
name: String, // Dynamic string
password_hash: String, // Argon2 hash
age: i16,
// ... other fields
}Required: Migration tool to convert existing BBS data to new format (or maintain backward compatibility).
Tool Requirements:
- Read Old Format - Parse Pascal binary files
- Convert Data - Transform to new Rust types
- Validate - Ensure data integrity
- Write New Format - Save in Rust binary format or structured format (JSON, TOML, SQLite)
Example Migration Tool:
// impulse-cli tool: migrate command
fn migrate_user_database(
old_path: &Path,
new_path: &Path,
) -> Result<(), BbsError> {
let mut old_file = File::open(old_path)?;
let mut new_db = UserDatabase::create(new_path)?;
// Read all users from old format
while let Ok(old_user) = read_legacy_user(&mut old_file) {
// Convert to new format
let new_user = User {
name: String::from_utf8_lossy(&old_user.name).into_owned(),
// Hash old password (or require password reset)
password_hash: hash_password(&old_user.password)?,
age: old_user.age,
// ... other fields
};
// Write to new database
new_db.insert(new_user)?;
}
Ok(())
}Alternative: Maintain backward compatibility by supporting both formats.
enum UserRecordFormat {
Legacy(LegacyUserRecord),
Modern(UserRecord),
}
impl UserDatabase {
fn read_user(&mut self, id: UserId) -> Result<User, BbsError> {
match self.detect_format()? {
UserRecordFormat::Legacy(_) => self.read_legacy_user(id),
UserRecordFormat::Modern(_) => self.read_modern_user(id),
}
}
}- Round-Trip Tests - Write with Rust, read with Pascal (and vice versa)
- Data Validation - Checksum verification, integrity checks
- Migration Tests - Convert real BBS data, verify all fields
- Performance Tests - Benchmark read/write speed vs. Pascal original
Sprint Allocation:
- Sprint 8-9: Implement binary file I/O with bincode
- Sprint 29: Create migration tools and test with real BBS data
The conversion order must respect module dependencies to avoid circular dependencies and minimize rework.
Source: pascal-dependencies.md, pascal-dependency-matrix.csv
Total Dependencies: 1,070 USES relationships Average Dependencies per Unit: 9.4
Top Dependencies (used by most modules):
| Module | Used By | Category | Priority |
|---|---|---|---|
| RECORDS | 93 units | Core Types | CONVERT FIRST |
| COMMON | 86 units | Common Utilities | Phase 1 |
| COMMON5 | 88 units | Common Utilities | Phase 1 |
| COMMON1 | 87 units | Common Utilities | Phase 1 |
| COMMON2 | 86 units | Common Utilities | Phase 1 |
| COMMON3 | 87 units | Common Utilities | Phase 1 |
| STRPROC | 88 units | String Utilities | Phase 1 |
| MYIO | 89 units | I/O Utilities | Phase 1 |
Top Consumers (use most modules):
| Module | Uses | Category | Priority |
|---|---|---|---|
| IMP | 69 units | Main Program | Phase 4 (last) |
| MENUS | 62 units | Menu System | Phase 3 |
| WFCMENU | 33 units | WFC Menu | Phase 4 |
| LOGON1 | 26 units | Logon | Phase 2 |
| LOGON2 | 23 units | Logon | Phase 2 |
| SYSOP2 | 21 units | SysOp | Phase 3 |
- Foundation First - Convert modules with zero dependencies and high impact (RECORDS, STRPROC, TIMEJUNK)
- Layer by Layer - Convert modules whose dependencies are already converted
- Defer Main Program - IMP.PAS (69 deps) must be converted last
- Circular Dependencies - Break circular deps by refactoring shared code into new module
Circular Dependency Detection:
Found via pascal-dependencies.dot graph analysis:
- COMMON ↔ OUTPUT
- MENUS ↔ NUV
- FILE* modules (multiple circular chains)
Resolution Strategy: Extract shared interfaces into new modules or use dependency injection.
Tool: Graphviz dependency graph available at pascal-dependencies.svg (556KB, 114 nodes, 1,070 edges)
Color Legend:
- Red: Main Program (IMP.PAS)
- Cyan: Core Types (RECORDS.PAS)
- Blue: Common Utilities (COMMON*.PAS)
- Orange: File Management (FILE*.PAS)
- Green: Mail/Message (MAIL*.PAS)
- Yellow: SysOp (SYSOP*.PAS)
- Purple: Miscellaneous (MISC*.PAS)
- Gray: Other modules
Comprehensive testing is essential to ensure behavioral equivalence between Pascal original and Rust conversion.
Source: SPRINT-03-COMPLETION-REPORT.md, risk-mitigations.md
Required Infrastructure:
- Unit Test Framework - Standard Rust testing (
#[test],#[cfg(test)]) - Integration Test Framework -
tests/directory with cross-crate tests - Property-Based Testing -
proptestcrate for complex logic - Binary Compatibility Tests - Read/write Pascal data files
- Characterization Tests - Test Pascal original as oracle for Rust conversion
Implementation:
// Unit test example
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_serialization() {
let user = User {
name: "testuser".to_string(),
age: 25,
// ...
};
// Serialize to binary
let encoded = bincode::serialize(&user).unwrap();
// Deserialize
let decoded: User = bincode::deserialize(&encoded).unwrap();
assert_eq!(user.name, decoded.name);
assert_eq!(user.age, decoded.age);
}
#[test]
fn test_binary_compatibility_with_pascal() {
// Read Pascal-generated USER.LST
let legacy_data = std::fs::read("tests/fixtures/USER.LST").unwrap();
let user: User = bincode::deserialize(&legacy_data).unwrap();
// Verify fields match expected values
assert_eq!(user.name, "sysop");
}
}| Risk Level | Coverage Target | Rationale |
|---|---|---|
| CRITICAL | 95%+ | Expert review, extensive testing required |
| HIGH | 85%+ | Senior dev + peer review |
| MEDIUM | 75%+ | Standard process |
| LOW | 60%+ | Basic validation |
Goal: Document expected behavior of Pascal original.
Method:
- Run Pascal original with test inputs
- Capture outputs
- Create characterization tests in Rust
#[test]
fn characterization_test_user_login() {
// Run Pascal original: IMPULSE.EXE with scripted input
// Capture output
// Compare Rust implementation output to Pascal output
}Goal: Test each converted function/module in isolation.
Method:
- Write unit tests before converting module
- Convert Pascal → Rust
- Run tests, iterate until passing
- Code review
Goal: Test interactions between converted modules.
Method:
- End-to-end scenarios (user login → file upload → message post → logout)
- Multi-module tests (file area + message base)
- Protocol tests (Telnet/SSH connections)
Goal: Ensure no breaking changes during development.
Method:
- Run full test suite in CI on every commit
- Performance regression tests (compare to baseline)
- Memory leak detection (valgrind, ASAN)
Platforms:
- Linux (Ubuntu 24.04, primary target)
- Windows 11 (secondary target)
- macOS (tertiary target)
CI Matrix:
# .github/workflows/test.yml
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable, beta]Setup: Maintain test BBS with sample data for integration testing.
Data:
- 100 test users
- 50 test messages
- 20 test files
- 10 test boards
- Real Impulse 7.1 data files (for binary compatibility testing)
Usage:
- Integration tests
- Manual testing
- Demonstration environment
38 modules (33.3% of codebase) are classified as HIGH or CRITICAL risk, requiring special handling.
Source: high-risk-units.md, risk-mitigations.md
Modules: EXEC, EXECOLD, RECORDS, COMMON, COMMON5, INSTALL, SCRIPT, IMP, MAIL7, BPTRAP, IMPDOS
Special Handling:
- Senior Developer Assignment - Only senior developers convert these modules
- Pair Programming - Two developers work together (driver + navigator)
- Extended Timeline - Allocate 2x normal time for CRITICAL modules
- Code Review - Mandatory peer review by another senior developer
- Extensive Testing - 95%+ coverage, property-based testing, manual testing
- Phased Conversion - Convert in small increments, test frequently
Example: RECORDS.PAS (Score 28, CRITICAL)
Challenges:
- DOS interrupts, inline assembly, process execution
- 830 lines, core type definitions
- 93 modules depend on it (highest dependency impact)
Strategy:
- Sprint 5: Full sprint dedicated to RECORDS.PAS
- Team: 2 senior developers (pair programming)
- Approach:
- Convert record types one at a time
- Write unit tests for each type
- Implement bincode serialization
- Verify binary compatibility with Pascal original
- Testing: 95%+ coverage, binary round-trip tests
- Review: Mandatory peer review + architecture review
Modules: WFCMENU, INITP, TMPCOM, TMPOLD, SYSOP2S, COMMON2, FILE5, LOGON1, ANSIEDIT, COMMON1, FILE8, DOORS, FILE1, SYSOP3, FILE12, MENUS, MISC2, CMD, SYSOP6, TIMETASK, MENUS2, EXECBAT, FILE2, NETFOSSL, SYS, SYSOP2D, ZIPVIEWU
Special Handling:
- Senior Developer Assignment - Senior or strong mid-level developer
- Code Review - Mandatory peer review
- Integration Tests - Test interactions with other modules
- Extended Testing - 85%+ coverage
Example: TMPCOM.PAS (Score 18, HIGH)
Challenges:
- Interrupt handlers (platform-specific)
- Inline assembly
- 754 lines, serial port communication
Strategy:
- Sprint: Allocated to Phase 4 (later conversion)
- Team: Senior developer
- Approach:
- Replace interrupt handlers with signal-hook (Unix) or SetConsoleCtrlHandler (Windows)
- Replace inline assembly with safe Rust or std::arch intrinsics
- Abstract serial port I/O behind trait
- Testing: 85%+ coverage, cross-platform tests
Week 1: Planning & Setup
- Sprint planning meeting (2 hours)
- Review analysis documentation
- Assign modules to developers
- Set up feature branches
Week 2: Implementation
- Convert Pascal → Rust
- Write unit tests
- Daily stand-ups (15 minutes)
- Mid-sprint check-in (1 hour)
Week 3: Testing & Review
- Integration tests
- Code review
- Sprint review (1 hour)
- Sprint retrospective (1 hour)
A module is considered "done" when:
- ✅ Converted - All Pascal code converted to Rust
- ✅ Tests Passing - Unit tests + integration tests passing
- ✅ Coverage Met - Test coverage meets target for risk level
- ✅ Reviewed - Code review completed and approved
- ✅ Documented - Migration notes documented
- ✅ Integrated - Merged to main branch
- ✅ CI Passing - All CI checks passing (format, lint, test, build)
- Create Feature Branch -
git checkout -b feature/convert-records-pas - Convert Module - Translate Pascal → Rust
- Write Tests - Unit tests + integration tests
- Run Quality Checks -
cargo fmt,cargo clippy,cargo test - Commit Changes - Conventional commits (
feat:,fix:, etc.) - Create Pull Request - Include migration notes in description
- Code Review - Address reviewer feedback
- Merge - Squash merge to main
- Update Documentation - Mark module as complete in conversion-order.md
Recommended Team Size: 3-5 developers
Roles:
- Tech Lead - Architecture, code review, CRITICAL modules
- Senior Developer - CRITICAL/HIGH modules, code review
- Mid-Level Developer - HIGH/MEDIUM modules
- Junior Developer - LOW modules, testing
- Daily Stand-ups - 15 minutes, async (Slack/Discord) or sync (video)
- Weekly Syncs - 1 hour, review progress, blockers
- Sprint Planning - 2 hours, every 3 weeks
- Sprint Review - 1 hour, demonstrate completed work
- Sprint Retrospective - 1 hour, continuous improvement
| Metric | Target | Measurement |
|---|---|---|
| Modules Converted | 114/114 (100%) | Count of completed modules |
| Lines of Code Converted | 39,079/39,079 (100%) | Total Rust LOC vs. Pascal LOC |
| Test Coverage | 80%+ overall | cargo tarpaulin |
| CRITICAL Modules Coverage | 95%+ | Per-module coverage |
| HIGH Modules Coverage | 85%+ | Per-module coverage |
| CI Success Rate | 100% | CI passing on main branch |
| Metric | Target | Measurement |
|---|---|---|
| Clippy Warnings | 0 | cargo clippy -- -D warnings |
| rustfmt Compliance | 100% | cargo fmt -- --check |
| Binary Compatibility | 100% | Round-trip tests passing |
| Cross-Platform Tests | 100% passing | Linux + Windows + macOS |
| Metric | Target | Measurement |
|---|---|---|
| User Login Latency | < 100ms | Benchmark vs. Pascal original |
| File Upload Throughput | ≥ Pascal original | MB/s comparison |
| Message Post Latency | < 50ms | Benchmark vs. Pascal original |
| Memory Usage | ≤ 2x Pascal original | RSS measurement |
| Concurrent Users | 100+ | Load testing with vegeta |
Target: 3-4 modules per sprint (average)
| Phase | Sprints | Modules | Avg/Sprint |
|---|---|---|---|
| Phase 1 | 8 | 28 | 3.5 |
| Phase 2 | 8 | 28 | 3.5 |
| Phase 3 | 8 | 28 | 3.5 |
| Phase 4 | 6 | 30 | 5.0 |
Note: Phase 4 has higher velocity due to parallelization and infrastructure reuse.
| Risk | Impact | Probability | Mitigation | Sprint |
|---|---|---|---|---|
| Binary Compatibility Failure | HIGH | MEDIUM | Design serialization strategy early, test with real data | 5, 8-9 |
| Platform-Specific Code Blocking | HIGH | MEDIUM | Create abstraction layer early, cross-platform testing | 6-7, 30 |
| Global State Refactoring Complexity | MEDIUM | HIGH | Design BbsState architecture early, incremental migration | 5, 6-7 |
| High-Risk Module Conversion Delays | HIGH | MEDIUM | Allocate senior devs, 2x time, pair programming | Throughout |
| Dependency Circular Dependencies | MEDIUM | LOW | Refactor shared code, dependency injection | As discovered |
| Performance Regression | MEDIUM | MEDIUM | Continuous benchmarking, optimization sprint | 31 |
Phase 1 (Sprints 3-10):
- ✅ Design BbsState architecture (Sprint 5)
- ✅ Implement binary file I/O with bincode (Sprint 8-9)
- ✅ Create platform abstraction layer (Sprint 6-7)
- ✅ Convert RECORDS.PAS with 95%+ coverage (Sprint 5)
Phase 2 (Sprints 11-18):
- ✅ Validate binary compatibility with real BBS data (Sprint 18)
- ✅ Extend BbsState for file/mail modules (Sprints 11-16)
- ✅ Performance baseline measurement (Sprint 18)
Phase 3 (Sprints 19-26):
- ✅ Protocol abstraction layer (Sprints 22-23)
- ✅ Cross-platform testing (all sprints)
- ✅ High-risk module conversion (SysOp, protocols)
Phase 4 (Sprints 27-32):
- ✅ IMP.PAS conversion (Sprint 27-28)
- ✅ Full system integration (Sprint 29)
- ✅ Cross-platform testing (Sprint 30)
- ✅ Performance optimization (Sprint 31)
Goal: Reduce sequential conversion time by 30-40% through parallel work.
Prerequisite: RECORDS.PAS (core types) must be complete before parallelization.
Once RECORDS.PAS is complete (Sprint 5), the following groups can be converted in parallel:
Modules: FILE0-FILE14
Rationale:
- Each file area module is relatively independent
- All depend on RECORDS.PAS (already converted)
- Minimal cross-dependencies within group
Sprint Allocation: Sprints 11-13 (3 sprints)
Team Assignment:
- Developer A: FILE0, FILE1, FILE2, FILE3, FILE4
- Developer B: FILE5, FILE6, FILE8, FILE9
- Developer C: FILE10, FILE11, FILE12, FILE13, FILE14
Modules: MAIL0-MAIL9
Rationale:
- Message system modules share similar structure
- All depend on RECORDS.PAS and COMMON*.PAS
- Can be split into message base (MAIL0-4) and networking (MAIL5-9)
Sprint Allocation: Sprints 14-16 (3 sprints)
Team Assignment:
- Developer A: MAIL0, MAIL1, MAIL2
- Developer B: MAIL3, MAIL4, MAIL5
- Developer C: MAIL6, MAIL7, MAIL9
Modules: SYSOP1-SYSOP11, SYSOP2*, SYSOP21, SYSOP3, SYSOP6-9, SYSOP7M
Rationale:
- System operator functions are largely independent
- Can be split into user management, file management, system config
Sprint Allocation: Sprints 19-21 (3 sprints)
Team Assignment:
- Developer A: SYSOP1, SYSOP2, SYSOP3, SYSOP6, SYSOP7
- Developer B: SYSOP8, SYSOP9, SYSOP11, SYSOP21
- Developer C: SYSOP2A-SYSOP2J (sub-modules of SYSOP2)
Modules: MISC1-MISC5
Rationale:
- Miscellaneous utilities, independent
Sprint Allocation: Sprints 14-16 (concurrent with MAIL*)
Team Assignment:
- Developer D: MISC1, MISC2, MISC3, MISC4, MISC5
Sequential Conversion:
- 114 modules × 3.5 modules/sprint = 33 sprints
- 33 sprints × 3 weeks = 99 weeks (23 months)
Parallel Conversion (Actual Plan):
- 30 sprints × 3 weeks = 90 weeks (21 months)
- Time Savings: 9 weeks (2 months, 9%)
Additional Parallelization (If Team Size Allows):
- With 5 developers, estimated time reduction: 30-40%
- Potential timeline: 18-21 months
Challenges:
- Merge conflicts (resolved with good branch hygiene)
- Integration issues (mitigated with frequent integration tests)
- Communication overhead (mitigated with daily stand-ups)
Mitigation:
- Daily stand-ups (15 minutes)
- Shared documentation (conversion notes, architecture decisions)
- Continuous integration (test on every commit)
Pascal Analysis Files:
- pascal-inventory.md - Complete inventory of 114 units
- pascal-unit-analysis.md - Detailed unit analysis
- pascal-dependencies.md - 1,070 dependencies documented
- pascal-dependency-matrix.csv - Structured dependency data
- pascal-globals.md - Global constants and variables
- pascal-overlays.md - Overlay system analysis
- pascal-interrupts.md - Interrupt handlers and assembly
- pascal-dos-specific.md - DOS function dependencies
- pascal-binary-formats.md - Binary file formats
- type-mapping.md - Pascal→Rust type mappings
- conversion-risk-assessment.md - Risk ratings
- high-risk-units.md - 38 high-risk units detailed
- risk-mitigations.md - Mitigation strategies
- conversion-order.md - Priority-ordered conversion plan
- dependencies.json - Machine-readable dependencies
- risk-data.json - Machine-readable risk scores
- SPRINT-03-COMPLETION-REPORT.md - Sprint 3 summary
- pascal-dependencies.dot - Graphviz dependency graph
- pascal-dependencies.svg - Visual dependency graph
Project Documentation:
- README.md - Project overview
- CHANGELOG.md - Version history
- CONTRIBUTING.md - Contribution guidelines
- CLAUDE.md - Project memory
Sprint TODO Files:
- to-dos/phase-1-foundation/ - Sprints 1-8
- to-dos/phase-2-core-services/ - Sprints 9-16
- to-dos/phase-3-advanced-features/ - Sprints 17-24
- to-dos/phase-4-polish-deployment/ - Sprints 25-32
Rust Resources:
- Rust Book - Official Rust documentation
- Rust by Example - Learn Rust with examples
- Rust std library - Standard library documentation
- bincode crate - Binary serialization
- serde crate - Serialization framework
- Tokio - Async runtime
Pascal Resources:
- Borland Pascal 7.0 Reference - Language reference
- Turbo Pascal Documentation - Historical documentation
BBS Resources:
- BBS History - BBS documentary
- ANSI Art - ANSI terminal codes
- Telnet Protocol - RFC 854
By Topic:
| Topic | Primary Document | Supporting Documents |
|---|---|---|
| Risk Assessment | conversion-risk-assessment.md | high-risk-units.md, risk-mitigations.md |
| Dependencies | pascal-dependencies.md | pascal-dependency-matrix.csv, dependencies.json, pascal-dependencies.svg |
| Type Mapping | type-mapping.md | pascal-globals.md, pascal-binary-formats.md |
| Platform Migration | pascal-dos-specific.md | pascal-interrupts.md, pascal-overlays.md |
| Conversion Order | conversion-order.md | pascal-dependencies.md, conversion-risk-assessment.md |
Document Status: Final Next Review: Sprint 4 (Configuration System implementation) Feedback: Update this document as conversion progresses to reflect lessons learned