目录
CesarCoelho

Release 5.0 (#191)

  • Cleans up wording in COM Archive XML

Removes misleading requirement 7 from retrieve (“use query for ordering”) — query does not guarantee ordering either, and retrieve takes explicit ids so ordering is trivially caller-controlled. Replaces “object identifiers” with “object ids” in the query comment. Replaces “allocate/allocating” with “assign/assigning” for the store id-assignment behaviour.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Rewrites COM Archive query operation comment

Replaces the original verbose and redundant description with clearer wording that leads with what the consumer can do.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes ObjectKey comment and cleans up COM Archive XML wording

ObjectKey comment was circular (“combines an object type and an object key”) — rewritten to clearly state it identifies a COM object by its type, domain, and id.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes NMFPackageBuilder temp file location and zip stream closure

The metadata temp file was written to the JVM working directory (repo root) instead of the destination folder, leaving package-metadata.properties behind at the repo root after each build. The zip output stream also lacked a finally/try-with-resources guard, so a failure mid-write would leave a corrupt .nmfpack with no central directory.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames providerId→providerName and ProviderSummary→Provider in COM Directory

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes network field from PublishDetails

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Reorders domain field to third position in Provider composite

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames ProviderDetails COM object to Provider in Directory service

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes PublishDetails and ServiceProvider; stores Provider as archive body
  • Removes the PublishDetails composite; add() now takes Provider directly
  • Deletes the ServiceProvider COM object; directory uses a single Provider COM object (renumbered to 1) whose body is the Provider composite
  • Simplifies add()/remove() to a single archive store/remove call
  • Fixes service-level requirement numbering gap (12–15 → 12)

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes network field from ServiceFilter composite

The network field was never functionally used — every call site passed the wildcard ‘*’. Removed the field from the XML, dropped the corresponding lookup requirement, and updated all 8 Java call sites.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes requiredCapabilitySets and renames serviceProviderId in ServiceFilter
  • Removes requiredCapabilitySets field from ServiceFilter; the field was never used — every call site passed an empty UShortList
  • Removes the corresponding capability-filtering block from lookup()
  • Renames serviceProviderId to providerName in ServiceFilter to align with the Provider composite field name
  • Updates all 8+ Java call sites accordingly

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds App Isolation page to Development Guide for Missions

Documents the four isolation modes (none, linux-userspace, bubblewrap, docker-containers), how to configure the appsIsolation plugin parameter, OS requirements for each mode, and a summary comparison table.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Reflows all RST docs from 70-char to 110-char line limit

Prose paragraphs and list items reflowed to 110 characters; code blocks, directives, toctrees, literal blocks, section underlines, and RST tables preserved verbatim.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Moves logging.properties from repo root into sdk-execution-environment resources

The file was previously copied from the repo root by the SDK assembly pom.xml; it now lives alongside the other SDK resources and the copy directive is updated to reference the new path.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes supportedCapabilitySets field from ServiceCapability composite

Field and its lookup requirement removed from area002-COM.xml; all ServiceCapability constructor call sites updated accordingly.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Flattens ProviderDetails into Provider and removes summary variable naming

ProviderDetails was only ever used as a single field of Provider; its two fields (serviceCapabilities, providerAddresses) are now direct fields of Provider. All call sites updated. Stale “summary” variable names (providerSummaryList, providerSummary, summaryList, providerSummaryToConnectionConsumer) renamed to plain provider/providers equivalents throughout.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Code cleanup

  • Rewrites platform-services doc with Adapter pattern, driver integration, and drivers directory

Adds frontend/backend contact-point framing, Adapter pattern explanation with ASCII diagram, driver integration section (CLI per-call and daemon vs JNI), drivers/ directory reference, and reframes the OPS-SAT property mechanism as mission-specific rather than the default approach.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes typo: renames SpaceMOApdapterImpl to SpaceMOAdapterImpl

The class name had a typo (“Apdapter” instead of “Adapter”) that was inherited by all callers. Renames the file and updates all references across core and the space-to-space examples.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Corrects GroundMOAdapterImpl usage docs

The previous text claimed nonexistent factory methods (forApp/forSupervisor) and described esa.mo.nmf.centralDirectoryURI as the ground-side mechanism for passing the Directory Service URI. The factory methods don’t exist on GroundMOAdapterImpl, and the property is a space-side convention used by the Supervisor to tell spawned child apps where its Directory Service is.

Replaces both with the actual ground pattern: retrieveProvidersFromDirectory plus the constructor that takes a Provider, with the URI supplied as a program argument.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Corrects annotation reference docs to match actual annotation classes

The @Parameter docs used the stale name “generationEnabled” — the actual attribute is “reportingEnabled” (matching the underlying MO XML field). The @Action docs claimed a “category” attribute that does not exist on the annotation, and omitted the real “rawUnit” attribute. The @ActionParameter docs listed “conditionalConversionFieldName”, “convertedType” and “convertedUnit” — none of which exist on the annotation.

Fixes both reference/annotations.rst and the prose in development-app/monitor-and-control.rst.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates filesystem doc to reflect the current on-board directory layout

The previous tree showed a libs/nmf path that no longer matches the Deployment.java constants. Replaces it with the actual standard layout (apps, drivers, etc, jars-nmf, jars-mission, jars-shared-libraries, java, logs, packages, public). Moves the legacy OPS-SAT-specific layout (libs/, expXYZ/) to the OPS-SAT page where it belongs, with a forward pointer to the standard layout for new missions.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes CLI invocation, sobel-example, conf.py metadata, and minor lint
  • tooling/cli.rst: replaces the bare Java class name with ./cli-tool.sh in the invocation example and all four code samples.
  • development-app/sobel-example.rst: removes dangling pointer to a non-existent apps/ tutorial.
  • docs/source/conf.py: updates copyright to 2021-2026 and adds Cesar Coelho to the author list.
  • development-mission/platform-services.rst: strips trailing whitespace.
  • development-app/index.rst: fixes title underline length mismatch.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Merges development-app/platform-services/ into a single page

Combines the per-service files (camera, gps, autonomous-adcs, sdr, optical-data-receiver, power-control, clock, artificial-intelligence, plus the folder index) into one platform-services.rst file. Heading hierarchy: page title, then per-service sections, then per-service subsections. Content is preserved verbatim — only heading levels changed.

Updates the seven cross-references that pointed at the old platform-services/* subpages.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes Orekit dependency step from app project setup

The orekit-resources artifact is the SDK’s bundled orbital-data set, used by the simulator and by the one specialised app (camera-acquisitor -system) that does on-board ground-target prediction. Listing it as a generic step in new-app setup mixed simulator-side concerns with app development.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes repeated XML pointer from each platform service section

Now that the per-service files are merged into one page, repeating “See area105-Platform.xml for the full operation list” once per service was noise. Replaces it with a single page-level note at the top pointing at the XML as the authoritative interface, and strips the redundant sentence from all seven service sections.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Splits Platform services docs by audience (consumer / simulator / mission)

development-app/platform-services.rst is now consumer-only: each service has a one-line summary, one or two sentences on what it does, a code sample, and a reference example where one exists. Removes the repeated per-service .adapter notes, the predictable XProviderServiceImpl/XAdapterInterface boilerplate, the inconsistent Simulated/Hardware adapter subsections, and the hardware-vendor name-drops.

tooling/simulator.rst gains the full platformsim.properties property matrix in one table (calling out the iadcs.adapter quirk for ADCS) and absorbs the per-service simulator config knobs.

development-mission/platform-services.rst gains a Reference mission hardware adapters table consolidating the OPS-SAT BST IMS-100, iADCS-100, OPS-SAT SDR, ɸ-Sat-2 multispectral imager, in-house ADCS, and Movidius VPU mappings.

Also corrects the Clock section’s reference-examples claim: neither publish-clock nor periodic-alert actually consumes the Clock Platform service — both schedule MC publications from the JVM clock via TaskScheduler. The Clock service currently has no SDK example, same as SDR and OpticalDataReceiver.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes stale M&C API references after composite and method renames
  • ActionDefinition no longer has a category field; updates the 5-arg constructor sample (with ActionCategory.DEFAULT) to the current 4-arg form (name, description, progressStepCount, arguments) in monitor-and-control.rst and worked-example.rst.
  • Removes the stale “Action categories are DEFAULT, CRITICAL, HIPRIORITY” sentence — the ActionCategory enum no longer exists.
  • Renames reportActionExecutionProgress to reportExecutionProgress in monitor-and-control.rst and sobel-example.rst (NMFProvider’s actual method name).
  • Replaces stale ActionCategory example in reference/mal-data-types.rst with current enums (Severity, ValidityState).

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes stale consumer-side API references across docs
  • consuming-services.rst: ActionInstanceDetails → ExecutionRequest; submitAction → executeAction; ParameterMonitorValueAdapter → ParameterAdapter (singular UpdateHeader/ObjectKey/ParameterValue in the notify signature); AlertMonitorEventAdapter → AlertAdapter and monitorEventRegister → monitorAlertRegister; ActionMonitorAdapter → ActionAdapter; ParameterValueList → ParameterValueDetailsList for getValue; fixed ParameterRawValueList constructor usage.
  • com-events.rst: EventReceivedAdapter → EventAdapter; corrected the monitorEventNotifyReceived signature to the actual 7-arg shape (UpdateHeader, ObjectLinks, Long eventId, Element eventBody).
  • development-mission/{supervisor,platform-services}.rst: bare NanoSatMOConnector → NanoSatMOConnectorImpl (the real class).
  • reference/mal-data-types.rst: ActionInstanceDetails example → ExecutionRequest.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames app-isl.rst to inter-satellite-link.rst

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds root-level launcher scripts to the SDK playground

Five convenience scripts are now placed at the SDK root after build: start_Supervisor.sh, start_CTT.sh, start_SimulatorManager.sh, start_CLI.sh, start_Celestia.sh.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Applies mo-xml conventions across COM, MC, SM, Platform area XMLs

Mechanical pass against the mo-xml skill: file header (copyright, namespace order, spaces around =), attribute ordering on services, operations, fields, composites, enumerations and items, capability sets with comment=””, removal of empty comment=”” on message stages, renumbered all mal:documentation elements in document order, and renamed Platform area-level errors to Title Case.

Sets a uniform area-comment style across all five areas: spelled-out name followed by “services” (e.g. “Common Object Model services”), with MAL as the documented exception (“Message Abstraction Layer”). Updates the mo-xml skill to document the new convention.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

  • Moves launcher scripts from SDK Execution Environment to SDK Playground

Reverts the scripts incorrectly added to sdk-execution-environment and adds them in the correct location: sdk/sdk-playground-environment/.

Five convenience scripts (run_Supervisor.sh, run_CTT.sh, run_SimulatorManager.sh, run_CLI.sh, run_Celestia.sh) are placed directly in the playground module directory and reference the build output at target/space-filesystem/nanosat-mo-framework/.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Detaches the sdk-execution-environment from the reactor

  • Removes duplicate dependencies

  • Removes duplicate dependency

  • Renames SM area from SoftwareManagement to SM in XML and Java

Updates area007-Software-Management.xml: area name attribute and all internal area=”SoftwareManagement” type references changed to area=”SM”.

Updates all downstream Java: import org.ccsds.moims.mo.softwaremanagement.* replaced with org.ccsds.moims.mo.sm.*, and SoftwareManagementHelper replaced with SMHelper across 39 files.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds testbed-performance module with CLI performance infrastructure

New testbed-performance module based on testbed-e2e provides the scaffolding for CLI and Supervisor performance measurements:

  • PerformanceResults: shared utility that records 3 timed runs per command, computes the average, and writes a structured results file
  • CLIHarness (cli package): spawns the CLI fat jar in a fresh JVM and measures wall-clock time per invocation
  • CLIPerformanceTest (cli.tests package): placeholder test wired to a live in-process Supervisor; test methods added in step 3
  • Package structure leaves room for a supervisor performance package

Adds four testbed-performance-jdkXX jobs to the GitHub Actions pipeline, each uploading performance-results.txt as a named CI artifact.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Implements CLI performance tests (step 3)

Adds CLIResult value class to carry elapsed time, output, and exit code from each CLI invocation. Updates CLIHarness.run() to return CLIResult. Updates PerformanceResults to accept CLIResult triples, write per-run .log files (tier-X-command-runN.log), and include OS/CPU/heap in the header. Implements four test methods covering tiers 1-3: –help, parameter list, software-management findPackage, and parameter get. Updates CI artifact paths to also upload the tier-*.log files.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes missing testbed-e2e dependency in performance CI jobs

testbed-e2e is not part of the root reactor, so it is never installed by the top-level mvn install. Add an explicit install step before running the performance testbed.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Makes testbed-performance independent of testbed-e2e

Copies SupervisorHarness directly into testbed-performance under its own package, reading nmf.perf.filesystem instead of nmf.e2e.filesystem. Removes the testbed-e2e compile dependency and the now-unnecessary CI install step.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes picocli from CLI tool and replaces with hand-written dispatcher

Replaces picocli with a minimal Args parser and a Dispatcher that routes by group + subcommand name, eliminating ~300 ms of startup overhead on the –help path (378 ms → 83 ms measured on JDK 11). Deletes three routing-only dead-code files (root MCCommands.java, SoftwareManagementCommands.java, mc/MCCommands.java). Also fixes a pre-existing NPE in aggregation subscribe when the archive returns null for an empty definition set, and adds a clear error message to archive dump_raw when -l is omitted.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds timestamp to performance artifact names and fixes result ordering

Appends the run timestamp to CLI performance artifact names so each CI run produces uniquely named zips. Switches PerformanceResults from LinkedHashMap to TreeMap so sections are always written in alphabetical order regardless of JUnit execution order.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Restores startup timing prints to CLITool

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Improves startup timing print messages in CLITool

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds app run/stop performance test and fixes stopApp hang

Installs the benchmark app into the performance testbed filesystem and adds a tier-3 test that measures runApp and stopApp three times each. Also adds a 30-second timeout to the stopApp lock.wait() so the CLI does not hang indefinitely if the app fails to stop.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Reduces stopApp timeout from 30s to 4s

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes COM Archive Events and cleans up ToDelete hard-coding

The archive event feature (ObjectStored, ObjectUpdated, ObjectDeleted) was off by default and unused everywhere. Removes the com:events block from the Archive service XML, all related code from ArchiveManager (globalGenerateEvents flag, eventService wiring, generateSources, generateAndPublishEvents, generatePublishEventsThread), and the two dead constants from Const. Also rewrites ToDelete with readable int parameters and inline comments identifying each object type by name, replacing the trainee’s raw UShort/UOctet magic numbers.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes ArchiveSync purge to delete only the synced objects

The previous logic deleted all instances of a hardcoded set of MC/SM object types up to latestSync, regardless of what the ground actually requested. Purge now tracks the exact objects retrieved and deletes them by instance ID when the ground confirms receipt via free(). Removes the layering violation (ToDelete enum encoding MC/SM types in the COM layer) and dead code (ObjectsReceivedAdapter was never instantiated, stdQuota was set but never consumed).

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes command injection in Clock.setTimeUsingDeltaMilliseconds action

Replaces ShellCommander (sh -c) with ProcessBuilder using an explicit argument array, so the ground-operator-supplied date string is never interpreted by a shell. Also pins SimpleDateFormat to Locale.US to guarantee ASCII month abbreviations regardless of the satellite OS locale.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes three bugs in Yannick’s SM/supervisor code
  • adcsNadirPointing was creating AttitudeModeSunPointing instead of AttitudeModeNadirPointing (wrong attitude mode, logic error)
  • ProcessExecutionHandler had a race condition: StringBuffer length(), substring(), and delete() were not atomic, so data could be lost when the timer task ran concurrently with a reader thread; fixed by synchronizing on the buffer in both the reader and the drain path
  • Removes verboseLoggingWarningSent dead field (Set never read or written)

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Cleans up MCSupervisorBasicAdapter

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames App COM object to AppDetails in AppsLauncher service

Updates the XML definition and all downstream Java references (APP_OBJECT_* → APPDETAILS_OBJECT_*).

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames CommandDetails composite to Command in CommandExecutor service

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Makes getTypeShortForm public static and marks it deprecated

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames NearbyPositionDefinition composite to NearbyPosition in GPS service

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Code cleanup

  • Code cleanup

  • Code cleanup

  • Code cleanup

  • Removes obsolete Windows startGUIPanel.bat (superseded by run_SimulatorManager.sh)

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Moves tail log scripts from simulator source tree to sdk-playground-environment

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Renames the script

  • Fixes CTT not displaying empty-string parameter values

Empty string raw values were indistinguishable from unlabelled cells in the published-values grid (ParameterLabel treats “” as “no value yet”). Display them as “” instead so the value is visible.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Rewrites MCSupervisorBasicAdapter without annotation machinery

Replaces @Parameter/@Action reflection with explicit registration matching the MCAllInOneAdapter pattern. Adds GPS, magnetometer, and attitude quaternion parameters via pull (onGetValue) and push (pushParameterValue from ADCSDataHandler). Default attitude monitoring interval changed from 0 s to 1 s so enableMonitoring starts on launch.

NanosatMOSupervisorBasicImpl simplified to hardcode PlatformServicesProviderSoftSim directly instead of reflective property lookup.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates the name of the client GUI Window

  • Code cleanup

  • Code cleanup

  • Code cleanup

  • Moves reference documents from SDK resources to docs/reference-documents/

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Refactors SimulatorNode by extracting three helper classes

SimulatorNode was a 3,767-line God class. Extracted:

  • NMEAFormatter: all 14 NMEA sentence types (case 2001)
  • FineADCSCommandHandler: FineADCS commands (cases 1001–1204)
  • ConfigurationManager: header/filter/scheduler/template IO

Also replaces the O(n) LinkedList command lookup with a HashMap<Integer, CommandDescriptor> for O(1) dispatch. SimulatorNode is now 1,407 lines.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates reference document paths after move to docs/reference-documents/

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates docs to replace sdk-execution-environment with sdk-playground-environment

All path references, script invocations, and deployment instructions updated to reflect the new SDK Playground Environment and its filesystem structure.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes last remaining execution environment reference in quickstart

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds hello-world app to SDK Playground and fixes quickstart reference

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes sdk-execution-environment, replaced by sdk-playground-environment

Updates sdk/README.md to reflect the new playground structure and commands.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes stale m2e lifecycle workaround section from sdk/README.md

The section referenced maven-antrun-plugin which no longer exists in the project.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes stale NMF_HOME export instruction and Package Assembler reference

NMF_HOME is now set internally by the supervisor and playground scripts; users no longer need to export it manually.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes network/NetworkZone concept from COM Archive and all services

The CCSDS MAL network zone field was never populated with meaningful data in NMF. Removes it from area002-COM.xml (ArchiveDetails, ArchiveQuery, CompactCOMObject), deletes FastNetwork, drops the column from the SQL schema, and replaces all ConfigurationProviderSingleton.getNetwork() calls with null across COM, MC, Platform, and SM service providers.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes unimplemented ObjectStored/Updated/Deleted event references from Archive op comments

These events were never published by the NMF Archive implementation.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Auto-fits column widths in Communication Settings table after data loads

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Adds monitorEvents PUBSUB to AppsLauncher and shutdown actions to Benchmark

Replaces the COM Event service subscription for app lifecycle tracking with a structured monitorEvents PUBSUB on the AppsLauncher service itself. Consumers now receive a typed AppEventType (START_REQUESTED, STARTED, STOP_REQUESTED, STOPPED, KILLED, EXITED, CRASHED) with optional exitCode and extraInfo fields, keyed by appName and appId. The CTT is updated to subscribe to monitorEvents and display event-driven status in the apps table. The Benchmark app gains three shutdown actions: shutdown.gracefully, shutdown.system.exit.0, and shutdown.system.exit.x (with configurable exit code).

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates NMF App Lifecycle docs with monitorEvents flowchart and AppEventType

Rewrites lifecycle.rst to document the structured app lifecycle introduced by the monitorEvents PUBSUB operation. Adds an AppEventType reference table (all 7 values with descriptions and exitCode presence), a flowchart showing Idle→Starting→Running→Stopping transitions, and four Mermaid sequence diagrams covering runApp, stopApp, killApp, and self-termination (EXITED/CRASHED). The monitorEvents operation is added to the operations list with subscription key details.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Moves Deployment tooling methods into DeploymentTooling subclass

Deployment.initialize() and reset() are build-time concerns that do not belong in the runtime Deployment class. DeploymentTooling extends Deployment and exposes both methods for use by Maven Mojos. The Mojo now calls initialize() at the start and reset() in a finally block, guaranteeing cleanup even on failure.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes off-EDT table model updates in CTT list response callbacks

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes stale identity model references from MC service impls and CTT

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes dead getAggregationValuesList method from AggregationManager

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Replaces COM Events with monitorEvents IPC, adds AppStarted/AppStopped archive records, adds AppLifecycleNominalTest
  • Removes StopApp/Stopping/Stopped/StartApp COM events from AppsLauncher service
  • Apps now subscribe to monitorEvents PUBSUB on Supervisor at startup to receive STOP_REQUESTED shutdown signals, replacing the old CloseAppEventListener mechanism
  • Deletes CloseAppEventListener and ClosingAppListener; stopNMFAppGracefully now waits directly on process exit
  • Adds AppStarted (COM object #2) and AppStopped (COM object #3) to AppsLauncher for archive-based lifecycle history; AppStopped captures stopReason and exit code
  • Adds AppLifecycleNominalTest with 8 tests covering start, stop, kill, monitorEvents notifications, and archive records; stopApp is known broken

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fixes app exit-code propagation, replaces “App: “ name hack with NMFProviderType

Two related fixes to the app lifecycle:

  1. stopApp delivery (name-match bug): NanoSatMOConnectorImpl matched the incoming STOP_REQUESTED event against the prefixed providerName (“App: x”) while the event carried the bare app name, so apps never shut down.

  2. Replaces the “App: “ provider-name prefix hack with a proper NMFProviderType field (APP/SUPERVISOR/MONOLITHIC/PROXY) on the Provider structure. Each composite now registers under its bare name with its type; consumers and the testbed select providers by type instead of string-prefix matching. Removes the PROVIDER_PREFIX_NAME, PROVIDER_SUFFIX_NAME, NANOSAT_MO_APP_IDENTIFIER_PREFIX and APP_PREFIX constants.

  3. Exit-code propagation: the generated start_app.sh piped java into ‘tee’, so in POSIX sh the script exited with tee’s status (0), masking the app’s real exit code (e.g. System.exit(18) was misclassified as EXITED instead of CRASHED). The launch line now captures the JVM’s $? into a sidecar .exit file and re-exports it, with explanatory comments in the generated script.

Adds verbose lifecycle logging across the stop path, and AppLifecycleNominalTest (10 e2e tests) covering start/stop/kill, monitorEvents notifications, the AppStarted/AppStopped archive records, and self-exit exit-code classification.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Removes the unused ConfigurationStored COM event from the Configuration service

The ConfigurationStored event was defined in the Configuration service XML but never used anywhere: no provider raised it, no consumer subscribed, and the Configuration service has no implementation. Removes the event definition, the five service-level requirements describing it, renumbers the surviving archive requirements, and drops the now-false claim that state changes are distributed via the COM Event service.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Adds monitorOutput PUBSUB to CommandExecutor service for live command streaming

Replaces the three fire-and-forget COM events (StandardOutput, StandardError, ExecutionFinished) with a proper PUBSUB operation that streams command output and exit code in real-time, keyed by commandId.

New CommandOutputType enumeration classifies notifications as STDOUT, STDERR, or FINISHED. The monitorOutput operation publishes typed output chunks with proper UpdateHeader subscription keys, enabling consumers to watch one command or all commands via wildcard filtering. Exit code (when FINISHED) is propagated inline with the output type.

The previous COM event mechanism is kept intact for archive persistence — each output notification is still stored via generateAndStoreEvent for historical queries. This sets up a clean separation: PUBSUB for live, Archive for history.

Updates the CTT (Consumer Test Tool) to subscribe to monitorOutput PUBSUB instead of the old COM Event service. The CommandExecutor tab now displays live streaming output as commands execute, via the real-time PUBSUB channel.

Next step: once this PUBSUB carries the live stream reliably, the three COM events can be safely converted to archive-only COM Objects (stored but not published), and the CommandExecutor will converge with AppsLauncher’s pattern.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Converts CommandExecutor COM events to archive-only COM Objects

Replaces the three fire-and-forget COM events (StandardOutput, StandardError, ExecutionFinished) with a unified CommandOutput COM Object that is stored in the archive for historical queries. The live PUBSUB stream via monitorOutput is now the exclusive real-time notification mechanism.

  • Removes com:event definitions from area007-Software-Management.xml
  • Adds CommandOutput composite (shortFormPart=5) with outputType, data, exitCode
  • Adds CommandOutput COM object (number=2) related to Command objects
  • Updates CommandExecutorProviderServiceImpl to store CommandOutput objects
  • Removes eventService dependency (no longer needed for Command Executor)
  • Cleans up dead code in AppsLauncherProviderServiceImpl that referenced CommandExecutor event constants
  • Updates CLI tool adapters (ArchiveToLogAdapter, ArchiveToAppListAdapter) to use CommandOutput object type instead of removed event constants

This completes the convergence from COM Events to PUBSUB for real-time streaming, with persistent archive storage via COM Objects instead of fire-and-forget events.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Removes COM Event service entirely from NMF

The Event service was a fire-and-forget mechanism that has been superseded by PUBSUB operations for real-time notifications and archive COM Objects for persistent storage. This commit completes the full removal:

XML & API:

  • Removes Event service definition from area002-COM.xml
  • Renumbers COM services sequentially (Archive 1, ArchiveSync 2, Directory 3, Login 4, Configuration 5)
  • Fixes operation numbering conflicts in Archive and ArchiveSync

Provider-side code:

  • Deletes EventProviderServiceImpl class
  • Removes event service initialization from COMServicesProvider
  • Updates ArchiveProviderServiceImpl.init() signature (no parameters)

Consumer-side code:

  • Deletes EventConsumerServiceImpl class
  • Removes event service init from COMServicesConsumer
  • Updates COMServicesConsumer.setServices() signature (archive only)
  • Removes eventService from DefinitionsManager

Service implementations:

  • Removes EventProviderServiceImpl import from AppsLauncherProviderServiceImpl

CTT (Consumer Test Tool):

  • Deletes EventConsumerPanel.java (no longer used)
  • Removes Event service UI elements and configuration from ConnectionConsumerPanel
  • Removes Event service tab creation from ProviderTabPanel

Example code cleanup:

  • Removes obsolete AlertTest2.java example files (2 copies) that depended on Event service
  • Fixes CLI tool BaseCommand to use updated ArchiveProviderServiceImpl.init()

All real-time notifications now use PUBSUB, and persistent storage uses archive COM Objects. The system is now cleaner and more consistent in its approach to IPC.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Restructure mo-services-impl into single unified module

Consolidate 4 separate service modules (COM, MC, SM, Platform) into one unified nmf-services-impl module at the mo-services-impl level, reducing build complexity and module interdependencies. Move the unified module up one level and delete old module directories.

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Fix parent pom relative path in mo-services-impl

After flattening module structure, update relativePath from ../../../ to ../../ to correctly point to parent pom.

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Merge nmf-environment into nmf-services-impl

Consolidate infrastructure utilities into the unified services module. Moves environment, deployment, and helper utilities from nmf-environment into mo-services-impl, reducing module count and simplifying dependencies.

  • Remove nmf-environment module from core/pom.xml
  • Remove nmf-environment from parent dependency management
  • Merge all source files and test resources into mo-services-impl
  • Add test resources config to build section

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Replace MOErrorException with dedicated exception classes

Use specific exception classes instead of generic MOErrorException:

  • InvalidArgumentException for invalid input arguments
  • UnsupportedOperationException for unsupported operations

Changes:

  • Rename MO errors: INVALID → Invalid Argument, DUPLICATE → Duplicate
  • Update XML error definitions and type references (4 area files)
  • Update Java provider implementations to throw dedicated exceptions
    • CameraProviderServiceImpl: 3 instances of InvalidArgumentException
    • AutonomousADCSProviderServiceImpl: 1 instance of UnsupportedOperationException
  • Update Java constant references: INVALID_ERROR_NUMBER → INVALID_ARGUMENT_ERROR_NUMBER

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Remove unused Installation COM object from PackageManagement service

The Installation COM object was defined but never used in the implementation. Remove it along with its SVG diagram references to clean up the specification.

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Rename Configuration service COM objects for naming consistency

Align COM object names with their body types:

  • ServiceConfiguration → ConfigurationService
  • ProviderConfiguration → ConfigurationProvider

Updates:

  • XML: area002-COM.xml object definitions
  • Java: ConfigurationServiceInfo constants
    • SERVICECONFIGURATION_OBJECT_TYPE → CONFIGURATIONSERVICE_OBJECT_TYPE
    • PROVIDERCONFIGURATION_OBJECT_TYPE → CONFIGURATIONPROVIDER_OBJECT_TYPE
  • Java: 6 files updated with new constant references

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Simplify Configuration service and enable persistence by default

Architectural simplification:

  • Remove ConfigurationSet COM object and composite (no longer needed)
  • Embed configuration data directly in ServiceConfiguration and ProviderConfiguration composites
  • Eliminate indirection through related links

Java interface updates:

  • ReconfigurableService/ReconfigurableProvider now use ObjectKeysList instead of ConfigurationSet
  • Update 6 service implementations (Action, Aggregation, Alert, Parameter, GPS, AppsLauncher)
  • Rewrite PersistProviderConfiguration and PersistLatestServiceConfigurationAdapter
    • No longer follow related links for ConfigurationSet
    • Extract configObjects directly from service configuration composites

Default behavior change:

  • Configuration persistence now enabled by default (was opt-in before)
  • Supervisor and Monolithic now consistent with Connector
  • Users can still disable via system property if needed

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Update testbed tests to use ObjectKeysList instead of ConfigurationSet

Fix compilation errors in testbed-area-com tests after ConfigurationSet removal:

  • ArchiveTest: Store and retrieve ObjectKeysList directly
  • ArchiveQueryCountTest: Replace ConfigurationSet with ObjectKeysList (2 locations)
  • Update test assertions to use ObjectKeysList methods (size(), get())

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Create NearbyPositionAlert composite to achieve 100% COM object naming consistency

Add NearbyPositionAlert composite in area002-COM.xml with:

  • Field: enteredBoundary (Boolean) - semantic indicator of boundary crossing direction
  • ShortFormPart: 31
  • Comment: “Alert state for spacecraft entering/exiting nearby position boundary”

Update COM object in area105-Platform.xml:

  • NearbyPositionAlert object body type: Boolean → NearbyPositionAlert
  • Now all 21 COM objects have matching names and body types (100% consistency)

This completes the architectural alignment goal: every COM object name matches its composite body type name across all MO service areas.

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Rewire GPSManager to use NearbyPositionAlert composite

Update storeAndGenerateNearbyPositionAlertId method in GPSManager.java:

  • Import NearbyPositionAlert composite from COM structures
  • Create NearbyPositionAlert instance with enteredBoundary field
  • Store the composite instead of raw Boolean (Union)

This completes the NearbyPositionAlert implementation by synchronizing Java code with the new XML composite definition.

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Remove unused preCheck method from ActionInvocationListener interface

Remove the preCheck() method that was required by the ActionInvocationListener interface but never actually used by any applications. All 21+ example apps ignored this method and relied on the default implementation that simply returned true.

Changes:

  • ActionInvocationListener: Remove preCheck() method signature
  • MonitorAndControlNMFAdapter: Remove preCheck() override
  • ActionManager: Remove preCheck() call, simplify validation to type checking only
  • SimpleParameterBackend (testbed): Remove preCheck() override

Impact: Cleaner interface without breaking changes. Apps only need to implement actionArrived() for action execution. Parameter/argument validation still occurs in ActionManager but without the unused custom pre-check hook.

All testbeds pass (15 tests), full build successful.

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Code cleanup: formatting and imports consolidation

Minor cleanup:

  • SimpleMonitorAndControlAdapter: Fix class declaration line wrapping
  • MCAdapter (benchmark): Consolidate MAL structure imports using wildcard

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Implement exception-based action error handling in NMF

Replace UInteger error codes with ExecutionFailedException in the action execution flow. Exception messages are automatically captured in the comment field of both ExecutionProgress (sent to ground) and ExecutionStatus (archived).

Changes:

  • ActionInvocationListener interface: changed actionArrived() to throw ExecutionFailedException
  • ActionManager: updated to catch exceptions and extract error messages for progress/status reporting
  • XML: added ExecutionFailedException error definition in area004-Monitor-and-Control.xml
  • All adapter implementations: updated signatures and implementations to use exceptions
  • Example apps: converted to exception-based error handling with descriptive messages
  • Testbed: added missing ExecutionFailedException import

Co-Authored-By: Claude Haiku 4.5 noreply@anthropic.com

  • Remove unused reportProgress param and fix action success-as-failure

Two follow-ups to the exception-based action error handling:

  • Drop the unused boolean reportProgress parameter from ActionInvocationListener.actionArrived() and all implementations, callers, the @Action annotation contract, and the reflection-based argument validation in MonitorAndControlNMFAdapter. It was a leftover from the old ActionDefinition and was never referenced anywhere.

  • Fix a regression where the mechanical UInteger-to-exception conversion turned action success paths (UInteger(0) / “return null // Success”) into thrown ExecutionFailedException, causing several example apps to report failure on every successful action. Affected: Waveform, MCSnapNMFAdapter, FiveStagesAction, edge-ai, python-script, picture-processor. Success paths now return normally, genuine errors throw descriptive messages, and unmatched actions throw “Unknown action: “.

  • Sort the new mc.ExecutionFailedException import before mc.structures across the affected files.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix @Action arg registration and migrate it to exception-based errors
  • Fix a regression from the reportProgress removal: registerActions still skipped 3 leading method parameters (copyOfRange(…, 3, …)) when there are now only 2 (executionId, interaction). This dropped the first @ActionParameter of every annotation-based action and broke invocation. Corrected to 2.

  • Remove the unused rawUnit() field from the @Action annotation. Raw units belong on the arguments (@ActionParameter), not the action; nothing set it and the framework never read it.

  • Migrate the annotation-based action API to the exception model: the framework ignores the method return value and failure must be signaled by throwing ExecutionFailedException. Updated the @Action javadoc example and converted all 22 @Action methods (payloads-test, camera-acquisitor-system) plus their backing handler methods from returning UInteger error codes (now silently ignored) to void + descriptive ExecutionFailedException.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Update docs to reflect exception-based action error handling

Bring the M&C app-development and annotation-reference pages in line with the new action backend interface:

  • @Action methods now return void and throw ExecutionFailedException on failure instead of returning a UInteger error code.
  • The boolean reportProgress parameter has been removed from all signatures.
  • The rawUnit attribute has been removed from @Action (it belongs on @ActionParameter, not the action itself).
  • Added a note explaining that the ExecutionFailedException message is automatically captured in ExecutionProgress (ground real-time) and ExecutionStatus (archive).

Files updated: monitor-and-control.rst, worked-example.rst, reference/annotations.rst.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fix dead-code wasted query and two missed exception migrations
  • PersistLatestServiceConfigurationAdapter: Remove the now-dead configObjectsObjId field and the if-block that performed a wasted archive lookup on every onConfigurationChanged call. After the ConfigurationSet removal, the update correctly uses serviceConfigObjId directly; the lookup result was never used. Remove the corresponding unused ArchivePersistenceObject import.

  • OpticalDataReceiverProviderServiceImpl: Complete the MOErrorException migration that was left behind with TODO comments. Replace the two generic MOErrorException(UInteger(0)) calls with InvalidArgumentException (null/zero duration) and UnsupportedOperationException (null data), in line with the rest of the codebase.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Update CLAUDE.md to match post-refactoring repository state
  • Module structure: drop merged nmf-environment, describe mo-services-impl as a single unified module, and replace the deleted sdk-execution-environment with sdk-playground-environment.
  • Key Composites table: remove the now-deleted COM Event service from the Connector and Supervisor stack descriptions.
  • @Action example: void return + throws ExecutionFailedException (no UInteger, no reportProgress).
  • Service Layer Hierarchy: drop Event from the COM area.
  • Rename “Running the SDK Locally” to “Running the Playground Environment” and rewrite the steps to use the run_Supervisor.sh / run_CTT.sh scripts and the target/space-filesystem output path.
  • Documentation Structure: ten sections (add the omitted mission-integration), with corrected development-* directory names.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix race between AppStopped archive write and stopApp UPDATE

stopNMFAppGracefully was calling sendUpdate (which releases the consumer latch in AppLifecycleNominalTest.stop()) immediately after process.waitFor() returned. The ProcessExecutionHandler monitor thread also reacts to the same process exit, calling processStopped() -> storeAppStopped() which enqueues the AppStopped archive insert. Because the archive uses a single-threaded FIFO executor, whichever thread enqueues first wins. The sendUpdate path was consistently faster than the DB path, so testAppStoppedInArchive queried the archive before the AppStopped record existed.

Fix: remove the explicit setRunning(false) from stopNMFAppGracefully and instead spin-wait (up to 5s, polling every 50ms) until isAppRunning() returns false, which only happens after processStopped() has enqueued the archive insert and cleared the flag. sendUpdate is sent only after that point, so the single-threaded FIFO executor serialises the consumer’s query behind the insert.

Also improve AppHarness.waitProcessGone() to log the app’s logfile (which includes the AppShutdownGuard thread dump when the JVM hangs on shutdown) on timeout, making it easier to diagnose what is blocking the process exit.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Code cleanup

  • Replace fixed 1s sleep in waitUntilRunning with Directory polling

The original waitUntilRunning() slept an unconditional 1 second after runApp() and then checked isRunning(). This was a heuristic: the app initialises in ~200ms locally, so 1 second was pure waste on every start.

Replace with a polling loop that queries the supervisor’s already-open Directory stub (no new MAL connection per poll) until the app’s own provider entry appears. Directory registration is the last step of NanoSatMOConnectorImpl.init(), so it is the definitive “fully initialised” signal: the monitorEvents subscription (for STOP_REQUESTED) and the Action service are both ready before the directory entry is added.

After the directory entry is found a 500ms buffer is kept to let the archive (H2) finish its startup/recovery phase. Without it, a System.exit() triggered immediately after registration catches H2 mid-recovery, making its shutdown hook take many seconds and causing waitProcessGone to time out.

Result: ~3.7 seconds saved across 10 tests (16.3s vs 20.0s), a consistent 18.5% reduction confirmed over multiple runs.

Also log the app’s log file in waitProcessGone’s timeout path; the log includes the AppShutdownGuard thread dump when the JVM hangs on shutdown, making it easy to diagnose what is blocking the process exit.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Rename opssat-gps-simulator to cubesat-gps-simulator

The module name reflected an OPS-SAT-specific origin but the simulator is generic and used across CubeSat missions. Rename the directory and update the parent pom module entry and README link accordingly.

The Java package (opssat.simulator) is shared with opssat-spacecraft-simulator and is left unchanged to avoid breaking the cross-module imports.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Rename opssat-spacecraft-simulator to cubesat-spacecraft-simulator

The module name reflected an OPS-SAT-specific origin but the simulator is generic and used across CubeSat missions. Rename the directory and update the parent pom module entry and README link accordingly.

The Java package (opssat.simulator) is left unchanged as it is shared across the simulator modules.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Align artifactIds with directory names
  • cubesat-gps-simulator: gps-simulator → cubesat-gps-simulator (update dependency reference in cubesat-spacecraft-simulator)
  • cubesat-spacecraft-simulator: spacecraft-simulator → cubesat-spacecraft-simulator (update dependency reference in platform-services-impl)
  • echo (ground): rename directory echo → echo-ground, EchoGround → echo-ground
  • echo (space): rename directory echo → echo-space, EchoSpace → echo-space
  • mo-services-apis: mo-services-apis-reactor → mo-services-apis
  • sdk: reactor → sdk

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Align remaining artifactIds and directory names
  • simulator: reactor → simulator (mission/simulator/pom.xml)
  • mo-services-impl/ → nmf-services-impl/ (directory rename, artifactId was already nmf-services-impl)
  • examples-space/ → examples-apps/ (directory rename, artifactId was already examples-apps)
  • mo-services-xml: nmf-xmls → mo-services-xml, including dependent references in all four api-nmf-* poms, parent/pom.xml, and the ccsds.specification.download.artifact property used by the API generator plugin
  • CLAUDE.md: update module structure paths accordingly

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Add diagnostics to e2e test assertion failures

Add AppHarness.getDiagnostics() which returns the app log and the last 100 lines of the supervisor log as a single string. Include it in the JUnit assertion message (only on failure) for the archive-record tests and the self-exit tests, so CI failure output contains the full app and supervisor logs without needing to fetch separate surefire report files.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Add NMFTest base class and test separators following MPD pattern
  • Add NMFTest abstract base class with SEP, SETUP_CLASS_SEP and SETUP_CLASS_MSG constants (mirrors MPDTest from mo-services-java)
  • AppLifecycleNominalTest extends NMFTest and prints explicit separators:
    • setUpClass: long separator + description before supervisor starts
    • each test: SEP / “Running: testXxx()” / SEP with literal searchable strings (not generated implicitly), so grep finds the code directly

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Minor cleanup in testbed-e2e harness classes
  • AppHarness: move ConnectionConsumer to explicit import, clean up inline FQN in waitForMonitorEvents
  • SupervisorHarness: add inline comment clarifying the readiness signal

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Increase supervisor startup/shutdown timeouts to 10s

3 seconds was too tight for CI environments with slower JVM startup. Also minor javadoc and style cleanup.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Remove ActivityTracking references from area007-Software-Management XML

Drops the com:activityUsage element from PackageManagement and the COM::ActivityTracking::OperationActivity SVG diagram node from AppsLauncher, as ActivityTracking has been removed from the COM area.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Remove Monolithic providers section from testing docs

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Improve testing docs: FlatSat section, CLI tool, SDK Playground naming

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Merge multistage-action into benchmark; fix echo-space pom copy-paste bug

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates the reporting period

  • IMprovement fixes

  • Adds Logger for catching issues

  • Apply consistent log format to all playground launch scripts

Pass -Djava.util.logging.config.file to Java in run_CTT.sh, run_CLI.sh, and run_Simulator_Client.sh so they use the same timestamp format as the Supervisor (run via start_supervisor.sh which already sets this flag).

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Implement getAreaXML() via AreaXMLExtractor with path traversal protection

Introduces AreaXMLExtractor to dynamically discover and load MO service XML files from classpath jars. Input is validated against the discovered whitelist before any resource load, preventing path traversal. Adds a JUnit test for the wildcard case.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fix AppHarness.waitUntilRunning() to scan log for URI instead of Directory poll

Polling the Directory service was susceptible to stale entries left by killed apps that never deregistered cleanly. Now mirrors SupervisorHarness: snapshots the app log file size before runApp(), then tails new log content for the “URI: …-Directory” line that NanoSatMOConnectorImpl emits on successful init.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Fix AppHarness.waitUntilRunning() to subscribe to monitorExecution PUB-SUB

The previous log-file approach was fragile: the app appends to the same log file across restarts, making it impossible to reliably distinguish stale URI lines from a previous killed instance. The Supervisor’s ProcessExecutionHandler reads the app’s stdout and re-publishes it via monitorExecution every second — subscribe to that before runApp() so no output is missed, then latch on the first “URI: …-Directory” line for this app. This mirrors exactly how SupervisorHarness reads from process.getInputStream().

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Extract LogScanner and AppArchiveQueries from test harness classes

LogScanner.extractDirectoryURI() removes duplicated URI parsing logic that existed identically in both SupervisorHarness and AppHarness. AppArchiveQueries moves the COM archive query boilerplate (queryByRelated, queryAppStarted, queryAppStopped) out of AppHarness into its own class; AppHarness delegates to it, keeping its public API unchanged.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Increase AppHarness startup timeout from 2s to 10s

The monitorExecution PUB-SUB flushes every 1s, so app startup time plus flush latency can easily exceed 2s on CI. Match the 10s timeout already used by SupervisorHarness.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Route testbed System.out banners through java.util.logging

All System.out.println/flush calls in testbed test classes replaced with LOGGER.info() so test banners and diagnostic lines go through the same ConsoleHandler as the INFO: framework log lines. This fixes interleaving of stdout and stderr visible in CI logs, where banner separators were landing mid-previous-test due to the two streams racing.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Updates to follow new v14 MO API

  • Ignore testMonitorEventsOnStart until mo-services-java v14 is adopted

The MAL broker drops concurrent PUB-SUB subscriptions from the same consumer when one is deregistered. The fix is committed in mo-services-java v14.0 but not yet adopted by NMF.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Set Provider type via constructor instead of removed setter

The MO v14 generator no longer emits setters on generated Composites, so Provider.setProviderType() is gone. Rebuild the Provider through its all-args constructor to attach the provider type, preserving the existing behaviour. The constructor and getters used here exist in both the current and the v14 MO APIs, so this compiles either way.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Update callers to use Attribute instance methods attribute2double/string

Follows the move of attribute2double/attribute2string/javaType2Attribute from HelperAttributes to the Attribute interface in mo-services-java. All callers with Attribute-typed variables now use the instance form.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Rename auto-placeholder argument names in pub-sub consumer overrides

Replace the generated _Identifier0 placeholder with subscriptionId in the beatNotifyReceived / streamRadioNotifyReceived overrides, and align iqComp with the overridden method’s iqComponents, for readability.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add MCP adapter SDK module

New sdk/mcp-adapter module exposing NMF MO operations as Model Context Protocol tools (McpAdapterServer, OperationToolMapper, McpTool, MoJsonConverter), registered in the SDK reactor.

  • Fix Provider type being lost from the published directory entry

loadURIs(name) registers the Provider in the directory via add() and returns that same instance. The previous code then rebuilt a separate Provider with the providerType and returned it, leaving the registered (and published) entry with providerType = null. Consumers rely on the provider type to wire up the SM services, so AppsLauncher could not be resolved (NullPointerException in GroundMOAdapterImpl consumers, e.g. the testbed-e2e AppLifecycle tests).

Set the providerType on the Provider before registering it: loadURIs(name) now delegates to loadURIs(name, type) which builds and adds the typed Provider in a single registration.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Adopt mo-services-java v14 MO API on NMF consumers

Bump the parent to 14.0-SNAPSHOT and migrate NMF to the v14 MAL API:

  • Pub-sub: consumers now receive the typed SubscriptionKeys accessor in the *NotifyReceived callbacks and read keys by name (trimming-aware) instead of positionally; param names match the overridden methods.
  • Attribute helpers: keep null-prone conversions on the null-safe static Attribute.attribute2X(…) form (instance form NPEs on null receivers).

Spans nmf-composites, nmf-services-impl, cli-tool, consumer-test-tool, example apps, and the e2e/area-mc testbeds. The attribute-helper and pub-sub changes share several files and require the v14 parent, so they are committed together.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Surface MO exceptions directly on provider Handler interfaces

Migrate all NMF provider service implementations to throw typed MO exceptions (e.g. InvalidArgumentException, UnknownException, DeviceNotAvailableException) directly instead of wrapping them in MALInteractionException, following the generator change in mo-services-java.

Update throws clauses on Handler override methods, propagate exceptions through internal helpers and managers, and fix all callers (composites, SDK examples, testbeds) to handle the newly-declared checked exceptions.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Move ExecutionStageType into monitorExecution subscription keys

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Depend on the released mo-services-java 14.0

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Track mo-services-java v14.1 for the docs generation workflow

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Detach mcp-adapter from the reactor build

The mcp-adapter is a proof-of-concept still in development and depends on the MCP Java SDK, which requires Java 17+. Building it as part of the reactor broke the JDK 11 build (and blocked the whole Java 11 test lane). Detach it from the reactor for now; it can still be built standalone via its own pom.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Catch typed UnknownException in MC definition registration

In v14 the MAL error hierarchy split: the typed UnknownException now extends MOErrorException rather than MALInteractionException, and the MC providers throw it directly from listDefinition. MCRegistration still caught MALInteractionException for the “these definitions are new” signal, so that recovery branch was bypassed and registration aborted with “The Parameters could not be registered!”, breaking app startup and the e2e testbed.

Catch UnknownException instead (in registerParameters, registerActions, registerAggregations, and registerAlerts) and read the new-definition indices from its extra information.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Debounce CTT table column packing to fix GUI freeze on large tables

Column auto-packing was wired to run on every TableModelEvent, so streaming N archive objects into a table queued N packColumns calls, each scanning all rows with prepareRenderer — O(N^2) work on the EDT. With ~3K objects from “Get All” in the Archive Manager tab, the GUI displayed the entries and then froze while the EDT drained the backlog.

Add TableUtils.packColumnsLater, which coalesces bursts of model events into a single pack via a per-table 150 ms one-shot Swing Timer, and use it at all five listener sites.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Remove the source field from the monitorAlert operation

The notify body carried a COM ObjectKey source next to the AlertEvent, but the same information is already conveyed through the archived AlertEvent’s COM sourceObject link, making the field redundant. This also aligns the NMF MC spec with the official MC v2 spec, whose monitorAlert carries no source field.

Drop the field from the publishNotify message and the corresponding service-level requirement, stop passing it on the provider publish side (the COM archive source link is unchanged), and update the consumers: the CTT alert log loses its Source column and the MC testbed adapter drops the parameter.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Remove the objKey field from the Parameter monitorValue operation

The notify body carried a COM ObjectKey next to the ParameterValue, but none of the consumers used it and the same information is already conveyed through the archived ParameterValue’s COM source link (which is unchanged: ParameterInstance keeps its source for the archive path).

Drop the field from the publishNotify message and its requirement note, stop passing it on the provider publish side, and update the Parameter service consumers (common MO adapter, CLI tool, payloads-test example, and CTT) plus the ground docs code sample, which also gains the previously missing subscription keys parameter. The Aggregation service’s own monitorValue operation is untouched.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Remove the objKey field from the Aggregation monitorValue operation

Completes the cleanup of the redundant COM key in the MC pub-sub notify bodies, after monitorAlert and the Parameter monitorValue. None of the consumers used it and the information remains available through the archived AggregationValue’s COM source link (the provider still passes the source to the archive store; it is only dropped from the publish).

Update the three consumers (common MO adapter, CLI tool, and CTT); the common MO adapter’s AggregationInstance now carries a null source, as it no longer travels over the wire.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Add missing area attribute to the CommandOutput related-object reference

The CommandOutput COM object’s related link referenced Command without the area attribute, so the api-generator looked up the object under a null area, warned “Unknown COM object referenced: TypeKey{null:CommandExecutor:1}”, and silently emitted a null related type in the generated COMMANDOUTPUT_OBJECT metadata.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Remove unused trimmedAppName variable from the AppsLauncher managers

  • Honor the apps isolation mode in the package upgrade path

NMFPackageManager.upgrade() changed the group ownership of the app directory on every Unix system, unlike install() and uninstall() which only do so under linux-userspace isolation. With the default isolation mode (none), upgrading a package attempted a sudo chgrp for a user that was never created, which fails (and hangs on systems where sudo prompts for a password). Guard the call with AppsIsolationMode.isLinuxUserspace() and only generate the per-app username in that mode, mirroring install().

Caught by the new Package Management e2e testbed.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Add package lifecycle traceability to the Package Management service

Mirror the App Lifecycle pattern (AppStarted/AppStopped) for packages: the install, uninstall, and upgrade operations now store PackageInstalled, PackageUninstalled, and PackageUpgraded COM objects in the archive, all related to the PackageDefinition object. The bodies carry the package name, the versions involved (from/to for upgrades), and the URI of the requesting consumer. The provider only stores an object after confirming the operation actually took effect on the backend.

Versions are read from the installation receipt through the new PMBackend.getPackageVersion(), backed by NMFPackageManager. The AppDetails source link to the removed PackageManagement object #2 is dropped: the two services’ lifecycles are traceable independently, and this resolves the “Unknown COM object referenced” build warning.

While wiring the install operation: send the computed integrity results in the ACK instead of a null body (which trips a message decoding NPE on the consumer), raise the validation errors before the ACK so they surface at the ACK stage, and fix the integrity checks to index availablePackages with the found index rather than the request index.

Completes the PMBackend javadoc along the way.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Add Package Management lifecycle tests to the e2e testbed

PackageManagementHarness drives the install, uninstall, and upgrade operations against the running Supervisor, queries the archive for the package lifecycle COM objects, and manufactures a newer package version for upgrade tests by copying the benchmark .nmfpack and bumping the version in its metadata.

PackageLifecycleTest covers the nominal lifecycle (uninstall, reinstall, upgrade with from/to version assertions), verifies that rejected operations store no phantom records, and scans the Supervisor log for silent archive-store failures. Archive assertions are made against baselines captured at start-up so leftovers from previous runs on the same filesystem cannot skew them.

The harness invokes the operations asynchronously: the sync variants hand the same lazily-decoded ACK body to both the calling thread and the listener dispatch thread, which races in the MAL layer of mo-services-java 14.0 (fixed in 14.1).

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Complete AppsIsolationMode with the missing mode check methods

Add isNone(), isDockerContainers(), and isBubblewrap() alongside the existing isLinuxUserspace(), and use isBubblewrap() at the AppsLauncher manager selection instead of the manual string comparison.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Rename PackageLifecycleTest to NMFPackageLifecycleTest

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Fix error type name: UNKNOWN -> Unknown in XML service specs

The MAL area defines the error as name=”Unknown” but all service XMLs referenced it as name=”UNKNOWN”. Align to the definition.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

  • Add SAVOIR-GS-002 Flight Computer Initialisation Sequence spec as reference

Reference document for aligning the upcoming NMF bootloader (image selection, integrity tests, gold fallback, boot report) with the SAVOIR terminology and initialisation sequence.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Add e2e test checking jars-* directories contain only .jar files

Currently failing: GenerateFilesystemMojo copies nmfpack-type artifacts into jars-mission because its catch-all else branch does not filter by artifact type. The fix comes in the next commit.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Keep non-jar artifacts out of the jars-* classpath directories

GenerateFilesystemMojo classified every resolved artifact into either jars-nmf or jars-mission, so nmfpack dependencies (declared for the install-packages goal) ended up in jars-mission. Skip any artifact whose file is not a jar; fixes FilesystemLayoutTest.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Add the NMF Bootloader specification and its SAVOIR-GS-002 mapping

Specifies the bootloader that will replace start_supervisor.sh: software baselines (primary/secondary/factory triples of framework, mission and Java runtime versions), a six-step boot sequence with integrity tests, Supervisor boot confirmation, and an autonomous fallback ladder, with Boot Reports following the NMF daily-log convention. A separate document maps the design to SAVOIR-GS-002 (terminology, environment assumptions, compliance matrix, deviations), applying the SAVOIR pattern at the application software layer.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Fix inconsistencies found in the bootloader spec review

Compliance matrix: BEF.05 and BPF.450 reclassified N/A (assumptions not featured, no NMF requirement traces to them), BAA.385/BMM.110 rows completed, Boot Report terminology row aligned with the daily-file model. Specification: failure detection bounded to exits before boot confirmation so commanded shutdowns do not feed the fallback ladder, critical/non-critical functions aligned with the actual self-tests, primary baseline version added to the Boot Report content, and the factory-exhaustion and unreadable-manifest corners specified.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Use ISO date and 24-hour time in the Supervisor log format

2026-07-05 20:16:38.162 instead of 2026 Jul 05 8:16:38.162 PM, matching the timestamp format of the bootloader Boot Reports.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Implement the NMF Bootloader (Phase 1: sequence, baselines, reports)

start_supervisor.sh is now the NMF Bootloader: a static POSIX-sh script (steps 1-5 of the Nominal Sequence) that selects the software baseline from the bootloader/ domain, verifies JAR checksums and the Java runtime, and writes step-by-step Boot Reports to ISO-dated daily files in logs/bootloader/ with a size cap. Baseline files degrade file-level: primary -> secondary -> factory.

The nmf-linux-maven-plugin gains BootloaderGenerator (baseline files, config, SHA256SUMS via the new ChecksumGenerator in nmf-package-lib, reused at install time in Phase 3) and no longer bakes any version or main class into the script. fresh_install.sh becomes setup_linux_userspace.sh, generated only for the linux-userspace mode, now also locking the bootloader/ domain and the factory baseline.

Confirmation step and fallback ladder (Phase 2) and the ASW integration (Phase 3) follow. Specification documents updated accordingly.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Implement the NMF Bootloader (Phase 2: confirmation and fallback ladder)

The bootloader now performs one boot attempt per invocation: after Execution it waits for the Supervisor’s boot confirmation marker (written by NanoSatMOSupervisor at init-complete) for up to boot-confirm-timeout-s. On confirmation the fallback state resets to the primary rung (self-healing); on failure (early exit or timeout, killing a hung JVM) it records the attempt and exits non-zero, so the next invocation - the restart loop belongs to the service manager, e.g. a systemd unit - applies the ladder: after boot-max-attempts consecutive failures the rung advances primary -> secondary -> factory.

Baseline selection starts at the persisted rung, keeping the file-level degradation below it. New e2e BootloaderFallbackTest drives the ladder through real script invocations; the harness teardown now TERMs the script first and relies on its cleanup trap. Specification and filesystem docs updated, including a sample systemd unit.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Make read-only a ParameterDefinition field; add ActionNotFoundException

Read-only was a dynamic ParameterStatusListener callback (isReadOnly), with a reflection branch in ParameterManager deciding name- vs id-based dispatch. Replace it with a first-class readOnly field on the ParameterDefinition composite (area004 XML), served by ParameterManager.isReadOnly from the stored definition. The setValue path already rejects read-only parameters with a ReadOnlyException before applying any value. All isReadOnly overrides and the callback are removed; every ParameterDefinition constructor call carries the new flag (annotation adapter from @Parameter(readOnly), supervisor telemetry read-only, others preserved).

Add a checked ActionNotFoundException to the actionArrived contract so a listener can signal “not my action” distinctly from “mine but failed” - the basis for composing multiple MC adapters. Existing adapters keep throwing ExecutionFailedException (narrowing is legal); the base and supervisor adapters throw ActionNotFoundException for unknown actions.

Add MC testbed tests for setting parameters: read-write set succeeds, read-only set returns a Read Only error, and a mixed batch is rejected atomically.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add the default Supervisor MC set (composite adapter) and CTT read-only support

Every NMF Supervisor now exposes a default set of MC parameters, present regardless of mission, as a contract for ground tooling and cross-mission reuse. NanoSatMOSupervisor.init composes the mission adapter on top of the default adapters via a CompositeMCAdapter, which the MC services see as one listener and which forwards each callback to its children (parameter reads: first non-null; actions: try each until one accepts, skipping ActionNotFoundException). The default set seeds SupervisorInfoMCAdapter (nmf.version, nmf.uptime) and MemoryMCAdapter (memory.ram/swap/pressure/page_faults/ECC errors from /proc and /sys), all read-only, under a dotted naming convention.

The MC adapter classes move to a dedicated esa.mo.nmf.mcadapters package (CompositeMCAdapter, DefaultSupervisorAdapters, SupervisorInfoMCAdapter, MemoryMCAdapter, MCSupervisorBasicAdapter); the public MonitorAndControlNMFAdapter base stays in esa.mo.nmf.

CTT Parameter panel: add a readOnly column and disable the setValue button for read-only (and unselected) parameters.

New e2e DefaultSupervisorMCTest verifies the default parameters exist alongside the mission’s, are readable, read-only, and that memory values are sane.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Put OK/FAIL first in the bootloader Boot Report status lines

Move the status to right after the step name (e.g. “INTEGRITY-TEST OK jars-nmf/5.0-SNAPSHOT” instead of “INTEGRITY-TEST jars-nmf/5.0-SNAPSHOT: OK”), so the status reads as a scannable column.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Implement the NMF Bootloader (Phase 3: ASW-side integration)

Adds the Supervisor-side integration the bootloader spec listed as Phase 3, so the framework can command and maintain the software baselines the shell bootloader reads.

  • SoftwareBaseline: a Java read/write model of a baseline-.properties file (the counterpart of the bootloader’s get_prop), with an atomic store.
  • ChecksumGenerator.verifyChecksums: verifies a directory against its SHA256SUMS in Java, reusing sha256Hex.
  • NMFPackageManager now, for baseline-component packages (nmf/mission/java): regenerates the SHA256SUMS of every baseline directory it writes into (BTE.02), rotates primary->secondary on a confirmed upgrade (REC.04), and rejects any install/upgrade/uninstall targeting the factory baseline (BMM.03). Metadata gains isNMF/isMission/isBaselineComponent.
  • BootloaderMCAdapter (a new default Supervisor MC adapter): exposes the three baseline files and the runtime state (rung, failed-attempts) as read-only parameters, and commands the primary baseline through a validated setPrimaryBaseline action. The action validates as reported stages (reportExecutionProgress) that the requested nmf and mission versions are installed and pass their integrity tests and that the Java runtime executes, then commits atomically; any failure rejects the whole command (BMM.02, REC.05). The secondary is not operator-settable (rotation only); the factory is immutable. Wired via DefaultSupervisorAdapters.create(this).
  • Docs: flip the bootloader-specification status note to fully implemented, align BMM.02 with the action-based commanding, and document the parameters and the action in the Supervisor page.

Tests: SoftwareBaselineTest and ChecksumGeneratorTest (unit); BootloaderMCTest (e2e) drives a live Supervisor on the generated filesystem, checking the read-only parameters mirror the on-disk baseline file and that a valid setPrimaryBaseline commits while a bogus one is rejected.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Restore the shared baseline file in BootloaderMCTest

The testbed-e2e module generates one NMF filesystem shared by every test class in a run. BootloaderMCTest commands setPrimaryBaseline, which rewrites bootloader/baseline-primary.properties on that shared filesystem; leaving the mutation in place made later test classes boot a bad baseline (JVM exits code 1, “CONFIRMATION FAIL - supervisor exited before confirming”), so the full e2e suite failed even though the class passed in isolation.

Snapshot the primary baseline file in @BeforeClass and restore it in @AfterClass so the shared filesystem is left as found. Full suite now passes.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Harden the bootloader baseline handling against injection

Review of the Phase 3 file operations surfaced a few injection gaps in the paths and file content derived from ground-supplied action arguments and from checksum manifests:

  • BootloaderMCAdapter.setPrimaryBaseline rejected path separators only in the version fields; main-class and java were written verbatim into the baseline properties file, so a newline in either could inject extra “key=value” lines. Stage 1 now rejects control characters (C0 + DEL) in all four fields.
  • SoftwareBaseline.store now throws on a line break in any field, the central guard for every writer of a baseline file (also the Package Management rotation path).
  • ChecksumGenerator.verifyChecksums rejected nothing in the manifest’s file names; a crafted SHA256SUMS with “../“ could make it read outside the directory. It now rejects entries containing a path separator or “..”.
  • BootloaderMCAdapter.onGetValue whitelists the baseline role before building a file name from it (defense in depth; not reachable by a consumer).

The java field is still executed for the runtime check, but via ProcessBuilder without a shell, so there is no shell-metacharacter injection; choosing the JVM is inherent to the feature.

Tests: SoftwareBaselineTest asserts store rejects a newline-bearing field; ChecksumGeneratorTest asserts a traversal manifest fails verification.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Centralise the baseline file name in Deployment

The “baseline-.properties” pattern was hardcoded in BootloaderMCAdapter (and the e2e test) alongside the existing Deployment.FILE_BASELINE_* constants.

Add ROLE_PRIMARY/ROLE_SECONDARY/ROLE_FACTORY constants and the helpers Deployment.baselineFileName(role) and Deployment.getBaselineFile(role), and express FILE_BASELINE_* in terms of a shared prefix/suffix. BootloaderMCAdapter and BootloaderMCTest now use these instead of building the name by hand.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Harden the cubesat simulator socket transport (CWE-502 + bind)

The simulator’s TCP transport (opssat.simulator.tcp) exchanged Java-serialized objects with no restriction and bound to the wildcard address regardless of the configured listenURL. A responsible-disclosure report (and a CodeQL hit) flagged both; verified against the source.

  • MultiThreadedSocketServer.run() resolved listenURL to an InetAddress but then called new ServerSocket(port, backlog), binding 0.0.0.0 and ignoring the operator’s address. Pass the resolved addr so loopback/management-only binds are honored.

  • Both the server (ClientServiceThreadReceiver) and the client (SocketClientThreadReceiver) called readObject() on a raw socket with no ObjectInputFilter, allowing an unauthenticated peer to drive class resolution (RCE if a gadget chain is on the classpath) or DoS via hostile object graphs (CWE-502). Install a shared SimulatorSerialFilter on both ObjectInputStreams: an explicit-class allowlist (the four simulator message types, the boxed scalar types + String, and the ArrayList/LinkedList/Date the protocol carries; java.lang.Number and java.lang.Object are included because the filter checks the whole serializable superclass chain and the collections’ backing Object[] array) plus maxdepth/maxrefs/maxbytes/maxarray limits, and rejects everything else. Deserialization only resolves these names against the server’s own classpath, so an allowed name can never be attacker-supplied code.

Native serialization is kept (a schema-based wire format would remove the class entirely and is a possible follow-up). New SimulatorSerialFilterTest round-trips every real message type and asserts disallowed classes and over-limit graphs are rejected.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Split the simulator deserialization filter into server/client allowlists

Running the soft-sim with the GUI client showed the single symmetric allowlist was wrong for the server->client direction: the server streams the simulator’s whole telemetry/data DTO family (SimulatorHeader, SimulatorData, SimulatorDeviceData, SimulatorSchedulerPiece, the command catalog, the platform Properties), which a four-class list rejected.

The two directions have different threat models, so use two allowlists:

  • serverFilter() (input from untrusted clients) stays strict: only the command types a client sends (CommandDescriptor and nested arg types), the scalar and collection JDK types, and the platform Properties, with a low maxrefs.
  • clientFilter() (input from the server the GUI chose to connect to) allows the simulator’s own packages (opssat.simulator.**) plus the JDK types, and a high maxrefs so the command catalog (many shared object references) is not false-rejected. maxbytes still bounds it. Deserialization only resolves these names against the client’s own classpath, so this permits only classes already shipped with the simulator; external gadget packages stay rejected.

Also add the JDK types the protocol actually needs, found via the filter’s own superclass/array checks: java.lang.Number (boxed numerics), java.lang.Object (collections’ backing Object[]), and Properties/Hashtable/Map$Entry (the platform config, sent both ways).

The filter now logs the rejected class (or exceeded limit) on rejection, and the GUI receiver appends that detail to its error line, so a blocked message is diagnosable instead of a bare “filter status: REJECTED”. Tests cover both filters, both directions, the config Properties, the high-reference catalog (allowed by client, rejected by server), foreign-class rejection and the depth limit.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix simulator device/scheduler telemetry never reaching the GUI

The Simulator client’s device tabs (FineADCS, GPS, Camera, …) and the Scheduler tab were always blank: the server never emitted the periodic device-data or scheduler-data feeds.

SimulatorNode.dataOut() returned only the first elapsed timer’s feed, while TaskNode.run()/manageTime() ticks and resets every timer each ~100 ms cycle regardless of what dataOut() returned. Because DEVICE_DATA (1000 ms) and SCHEDULER_DATA (5000 ms) are exact multiples of SIMULATOR_DATA (500 ms), SimulatorData (checked first) won every time they coincided and the device/scheduler elapsed flag was then silently reset — so those feeds were never sent.

Collect every periodic feed whose timer elapsed in a cycle into a small pendingPeriodicOut queue and emit one per dataOut() call, so coinciding feeds are no longer dropped. Contained to SimulatorNode; the shared TaskNode and the timer semantics are untouched.

Verified against a running MainServer with a raw socket probe: 20 x LinkedList over 20 s (was 0), SimulatorData still 2/sec with no regression.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add operation-level requirements and clean up the Platform service XML

The Platform services had operation-level requirements on only a handful of operations. Add a small, testable requirement (or two) to every operation that was missing one, capturing the provider behaviour without duplicating field or error descriptions. Also tidy up several long-standing issues in the same file:

  • Replace the fragile “-1” float sentinel in ReactionWheelParameters with the NULL-means-unchanged pattern (fields made nullable, requirement reworded).
  • Rename the ReactionWheelParameters field “parameters” to “rwParameters” so it does not clash with the MC Parameter service concept.
  • Model the reaction wheel controlMode as a ReactionWheelControlMode enum instead of a magic-value Integer.
  • Fix a duplicate shortFormPart (ReactionWheelIdentifier 12 -> 32).
  • Move the reaction wheel maximum-speed safety limit out of the maxSpeed field description into an Invalid Argument errorRef on setAllReactionWheelParameters, and enforce it (plus a device-availability check) in the generic AutonomousADCSProviderServiceImpl, using a constant derived from 10 000 RPM.
  • Rephrase the two wildcard requirements as provider behaviour.
  • Fix typos and description errors (identifier, day, Satellite, an AI, the rotated RGB camera gains, the dimensionless eccentricity, casing) and the setDesiredAttitude pseudo-requirement (moved to an inline Note).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Merge the parent POM into the root POM and remove the parent module

The build had a separate parent/ module (int.esa.nmf:parent) providing the dependency management, plugin management, properties and profiles, with the root aggregator (int.esa.nmf:nanosat-mo-framework) as its child. This split is the less common Maven layout.

Fold parent/pom.xml into the root pom.xml so the root serves as both the reactor and the parent, inheriting directly from the external int.esa.ccsds.mo:parent:14.0 - the same single-root layout used by projects such as WildFly. Every module’s is repointed from ‘parent’ to ‘nanosat-mo-framework’ with the relativePath adjusted accordingly, and the parent/ directory is removed.

The root’s maven.deploy.skip=true property is intentionally dropped: it would now be inherited by every module (skipping their deployment), and the merged pom, being the parent, must itself be installable/deployable.

Verified: both reactors validate (mvn validate at the root and for testbeds), and a module build through the merged reactor (nmf-composites -am) succeeds, confirming the moved dependency/plugin management still resolves.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Document the mission.properties file for mission and spacecraft designation

Add docs/source/development-mission/mission-properties.rst describing the mission.properties file the nmf-linux-maven-plugin generates into etc/. It specifies the file’s fields (mission.name, spacecraft.name, spacecraft.node, spacecraft.scid, organization.abbreviation, organization.name), how the addressing fields map onto the MO network zone, and how the design is grounded in the CCSDS SANA registries (SCID and Organization) where a standard exists and in NMF conventions where none does (mission grouping and the within-mission node number). Worked examples cover a single spacecraft (OPS-SAT), a spacecraft on a non-CCSDS link with no SCID (Phi-Sat-2), an agency constellation (Galileo, with a note that the SCID is not the Galileo SV ID), a mission inside a wider programme (Sentinel-1 under Copernicus), and anonymised commercial and mega-constellation cases. Register the page in the development-mission toctree.

The Maven wiring that supplies these values is deferred and flagged as such.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Stop the docs build from deleting the repository’s test sources

docs/source/conf.py cleaned up generated javadoc stubs with find . -name '*Test*' -delete. Because Sphinx executes conf.py and the find path is relative to the process working directory, running the docs build from the repository root deletes every Test file in the whole tree. Scope the cleanup to the javadoc output directory (find ./javadoc ...) so it can only ever touch the generated stubs.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Generate etc/mission.properties from the nmf-linux-maven-plugin

The plugin now writes a mission.properties file into the generated filesystem’s etc/ directory, describing the mission and spacecraft designation: mission name, spacecraft name/node/SCID and organization abbreviation/name. The values come from a nested configuration element on the generate-filesystem goal, backed by a new Mission POJO with flat camelCase fields (missionName, spacecraftName, spacecraftNode, spacecraftScid, organizationAbbreviation, organizationName) mapped onto the dotted property keys of the file.

Required fields (missionName, spacecraftName, organizationAbbreviation) are validated; spacecraftNode defaults to 1; spacecraftScid and organizationName are omitted when absent. Adds Deployment.FILE_MISSION_PROPERTIES, a FilesystemGenerator.addGeneratedFile writer, the block to the four filesystem-generating modules, a MissionTest unit test, and a documentation page section.

Parsing the file into the MO network zone at runtime is left for a follow-up.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Rename the MO service area XML files for the area renumbering

Pure git rename of the four service area definitions to their new area05N-*.xml filenames, kept as a separate commit so git records them as renames rather than delete+add. The area numbers inside the files and every reference to the old filenames are updated in the following commit.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Renumber the MO service areas: COM 51, MC 52, SM 53, Platform 54

Change the MAL area numbers of the four NMF service areas (MAL stays 1): COM 2->51, MC 4->52, SM 7->53, Platform 105->54. Updates the mal:area declarations in the renamed XML files, the api-nmf-* generator filters (each module’s own download.filter plus the COM ref-filter in MC/SM/ Platform), the AreaXMLExtractor javadoc example and the DirectoryProvider classpath test, and the documentation references.

Cross-area type references use area names, so they are unaffected. The api-nmf-* jars are generated from this XML at build time, so the new numbers propagate on the next full build.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Move the NearbyPositionAlert composite from the COM area to Platform

The NearbyPositionAlert composite (a single enteredBoundary Boolean) is a GPS/Platform-specific type but was defined in the generic COM area, so its generated class landed in org.ccsds.moims.mo.com.structures and the GPS provider imported it from there. It belongs in the Platform area alongside NearbyPosition.

Remove the composite from area051-COM.xml, add it to area054-Platform.xml with a Platform shortFormPart (33), repoint the NearbyPositionAlert COM object’s body type from the COM to the Platform area, and update the GPSManager import to org.ccsds.moims.mo.platform.structures. The COM-object naming consistency (object name == body type name) is preserved; only the area is corrected.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add the FPGA Platform service for per-app partial reconfiguration

New Platform service (number 10) that loads and unloads gateware modules – partial bitstreams – into the reconfigurable partitions of the platform FPGA at runtime, without disturbing the static shell design. Bitstreams are compiled on ground against the mission’s shell, delivered inside the app’s NMF Package, and declared by a sidecar module manifest (shell version plus one bitstream variant per partition, with CRC-32 checksums).

Operations: listPartitions, loadModule (PROGRESS, with per-stage UPDATEs), unloadModule (idempotent), getStatus, and the monitorPartitions PUB-SUB. The service allocates the partition – the app names its module and receives the allocated Partition back, including the dataPlaneRef (e.g. a Linux UIO device path) for direct data-plane access; MO carries only the control plane. Every load and unload is archived as an FPGAModuleLoaded/FPGAModuleUnloaded COM object, the unload related-linked to the load it terminates. Two new Platform area errors: Incompatible and Verification Failed.

The provider owns all policy (manifest lookup, shell-version compatibility, checksum verification, allocation, occupancy bookkeeping, archiving, publishing) behind a mechanics-only adapter SPI, so platform adapters stay thin. A software-simulator adapter (two partitions, shell sim-v1) is wired into the SoftSim platform provider for playground/CTT testing. The intended hardware target is the Zynq UltraScale+ via the Linux FPGA Manager and device-tree overlays; that adapter is a follow-up, as are the packaging metadata, supervisor lease-reaping, and the staged shell-update path through the bootloader baseline ladder.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Inject the supervisor into MCSupervisorBasicAdapter through the constructor

Replace the no-arg constructor plus setNmfSupervisor() setter with a constructor parameter and make the field final. The adapter dereferences the supervisor throughout without null checks, so requiring it at construction removes the temporal coupling that allowed an adapter to exist without one. Both supervisor mains (simulator and barebone) are updated. Also collapses the java.io imports in NMFProvider.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Complete the COMObjectEntity move into the archive.db package

The previous commit unintentionally carried the staged file rename (and the entities package-info deletion) without the accompanying source edits, leaving the moved file with its old package declaration. This commit completes the move: the package declaration of COMObjectEntity, the dropped same-package COMObjectEntityPK import, and the import updates in the nine using classes. The entities package held only this class; its composite key and every user already lived in archive.db. The COMObjectEntity occurrences in the SQL strings are the table name, not the Java type, and are unaffected.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Complete the COMObjectWindow move into the CTT utils package

Companion to the file rename carried by the constructor-injection commit: updates the package declaration of COMObjectWindow and the imports of its two consumers. The window is generic COM-object plumbing rather than a service panel, and its primary consumer (SharedTablePanel) already lives in utils; the windows.element subpackage stays where it is.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Renumber the FPGA service from 10 to 6

Reuse the Platform service number freed by the retired Magnetometer service, making the Platform numbering contiguous (1-9). The reuse is safe because the area itself was renumbered from 105 to 54 in this same unreleased cycle, so the (54, 6) wire identity has never shipped; the Magnetometer only ever existed as (105, 6). The FPGA service block moves into numeric position in the XML and the now-obsolete note about numbering gaps is dropped from the services reference.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Replace the Clock Platform service with a Heartbeat getTime operation

The Clock service required a full MO consumer/provider round trip to read time, adding milliseconds of thread-scheduling jitter to the one measurement that transport latency directly corrupts. Its on-board plumbing (SystemClock plus PlatformClockCallback, registered by every app connector) had no callers at all, and the monitorTimeFactor PUB-SUB was declared in the XML but never published nor subscribed. On-board code reads time from the system (Time.now()), as it always effectively did.

The one legitimate use – ground asking a provider for its notion of time – moves to the Heartbeat service (SM area) as a single getTime operation returning both the timestamp and the time factor, replacing the two separate Clock operations. Since every app provides Heartbeat, ground can now query the time view of each app, not only of the platform. The Heartbeat provider answers with Time.now() and a pluggable time-factor supplier (default 1); the simulator supervisor wires the simulation’s acceleration factor into it.

The Clock service is removed from the Platform area, ArtificialIntelligence is renumbered from 9 to 8 to keep the area contiguous (safe pre-release, as for the earlier FPGA renumbering), and the CTT Clock tab, the softsim clock adapter, the clock.adapter hybrid hook and the aggregation wiring are removed. The documentation loses the Clock sections, including a claim about commanded time updates that never matched an actual operation. This commit also carries a consolidation of ProviderTabPanel (unused provider field and commented Common block dropped, imports collapsed).

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Widen the CTT startup window to 1380 pixels

Also drops a redundant same-package import in DirectoryConnectionConsumerPanel.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Sync the CTT main form with its generated code

The .form file declared 800x600 maximum/minimum/preferred sizes on the tabs component that were absent from the generated initComponents() block, so opening the form in the NetBeans GUI Builder kept regenerating those lines – and committing them would have capped the tabs area at 800x600 inside the 1380x720 window. Drop the three properties from the form; the frame-level sizes stay.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Rename the FPGA Partition types to FPGAPartition and FPGAPartitionState

The upcoming SoftwareImages Platform service manages hypervisor partitions and needs partition types of its own, so the FPGA service’s generic Partition and PartitionState names would collide at the Java level and read ambiguously in a shared area. Prefix them with the owning service, following the convention set by the FPGAModuleLoaded/FPGAModuleUnloaded COM objects. Operation and field names (listPartitions, partitionId, preferredPartition) are unchanged.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Add the SoftwareImages Platform service for hypervisor partitions

New Platform service (number 9) that starts, stops and restarts software images – bare-metal binaries or guest operating systems – in the partitions of the platform hypervisor, without disturbing the other partitions. It is the runtime successor of the original 2016 SoftwareImage SM service, whose non-runtime capabilities were long since reincarnated elsewhere: image delivery and integrity in PackageManagement, baseline-plus-delta patching in the delta package type, and the main/redundant boot-image requirements in the bootloader baseline ladder. Only the execution dimension was missing.

Images are compiled on ground against a specific hypervisor configuration version and delivered inside an NMF Package with a sidecar manifest declaring that version and one image variant per partition. The service allocates the partition (the consumer names the image; a preferred partition is optional), verifies the CRC-32 and the configuration compatibility, and reports the start stages through a PROGRESS interaction. Every start and stop is archived as a SoftwareImageStarted/SoftwareImageStopped COM object, the stop related-linked to the start it terminates. The existing Platform errors are reused; no PUB-SUB is defined yet – partition state monitoring is deferred until a hypervisor adapter can feed health-monitor events.

The design mirrors the FPGA service deliberately: both load executable content onto a platform compute substrate behind a mechanics-only adapter interface, which is also now stated as the Platform/SM dividing line in the mission documentation. The reference hypervisor target is XtratuM through a mission-provided adapter (exec-based, no JNI); this commit ships the open piping only – service XML, provider with all policy, adapter interface, image manifest, consumer, aggregation wiring, and a simulated adapter with two partitions. The docs additionally gain the FPGA rows that were missing from the concepts list and the adapter tables.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Renumber the Camera, GPS and AutonomousADCS operations and capability sets

Three Platform services carried irregular numbering: Camera had capability set 36 and operation 15 amid otherwise low numbers plus a gap at operation 3, GPS skipped capability set 10, and AutonomousADCS jumped to the twenties for its last five capability sets and operations. Renumber both sequences sequentially in declaration order for every service; all Platform and SM services are now strictly sequential. Safe pre-release: the area was renumbered to 54 this cycle, so none of these wire identifiers has shipped.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Fix error contracts: SDR review, ALL_CAPS error names, undeclared device errors

Review of the SoftwareDefinedRadio service surfaced a class of contract defects where a provider returns an error that the service XML never declares, which the implementation had to smuggle out by wrapping the typed exception in a generic MALInteractionException. Declaring the error instead lets the provider throw it directly and makes it part of the API.

SoftwareDefinedRadio: declare Device Not Available on enableSDR and updateConfiguration (previously thrown but undeclared); make the enable and configuration fields non-nullable and document the NULL semantics of the remaining optional fields, adding the conditional requirements for applying the initial configuration and for supplying the publishing period; split the streamRadio requirement into its two separate obligations; and reword the enable field comment. OpticalDataReceiver.recordSamples and AutonomousADCS.enableMonitoring get the same Device Not Available treatment.

Also sweep every service area for error references still written in the old ALL_CAPS style that the error refactoring had missed: TOO_MANY in COM, INTERNAL in Software Management, and UNSUPPORTED_OPERATION and INTERNAL in Platform become Too Many, Internal and Unsupported Operation. Error definitions were already all Title Case.

The remaining MALInteractionException-wrapped errors in the batch-validation operations of Software Management, COM and MC are left for a separate pass.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Declare the batch-operation errors that were returned but undeclared

Category B of the error-contract review: three operations returned a typed error that their service XML never declared, forcing the implementation to smuggle it out wrapped in a generic MALInteractionException.

AppsLauncher.stopApp gains the Unknown and Invalid Argument errors (mirroring killApp, with the per-index UInteger extra information); PackageManagement’s checkPackageIntegrity gains Invalid Argument for packages that are not installed; and ArchiveSync’s retrieveRangeAgain gains Invalid Argument for an unknown transaction ticket. Each provider now throws the typed exception directly instead of wrapping it.

Widening the provider handlers required two in-process callers – the Supervisor’s shutdown path and the package manager’s stopAppIfRunning – to also handle InvalidArgumentException; the other callers use the asynchronous adapter form, whose signature is unchanged.

The two remaining wrapped errors are left deliberately: one is inside a private parameter-conversion helper (not a service operation), the other in a private simulator helper.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Remove the vestigial settings.properties traces

settings.properties is dead: nothing in the framework generates it, its pollgps/gpspollrate keys are read by no code, and its only real job – forming the MO network zone through MissionName and DeviceName – is superseded by the new mission.properties file. The only live trace was AuxFilesGenerator writing a dangling esa.mo.nanosatmoframework.provider.settings=settings.properties line into every generated app provider.properties, pointing at a file that is never produced.

Drop that generated line, delete the one leftover benchmark/settings.properties, remove the settings.properties reference from the two orphaned test fixtures and from the three documentation pages, and update the “Loads:” comments in the four provider composites. HelperMisc upstream still supports loading such a file, but nothing in NMF points it there anymore.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Configure the Supervisor transport in-process instead of from files

The Supervisor has no provider.properties of its own, so calling HelperMisc.loadPropertiesFile() only produced “file not found” warnings for provider.properties and transport.properties and left the transport on defaults anyway – in deployment (working directory is the NMF root, not etc/) and when running from the IDE alike.

Set the maltcp transport, encoding and autohost defaults directly as system properties via putIfAbsent (so a command-line -D still wins), and set HelperMisc’s own PropertiesLoadedFlag skip guard so any later loadPropertiesFile() call becomes a no-op. The MAL context factory already defaults to MALContextFactoryImpl when unset, so nothing is lost by not reading the files. This is also the seam where the mission.properties network zone will be injected.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Review the Aggregation service and align MC definition-management naming

Full review of the Aggregation service in area052:

  • Fix addAggregation: the request field comment wrongly claimed “The name and the AggregationDefinition” (the name is a field of AggregationDefinition), the field name was a misleading “…Details”, and the two singular requirements are merged into one iterative one.
  • Use “ids” / “definitions” for the definition-management operations, matching the Parameter and Action services (Aggregation previously used definitionIds / aggregationDefinitions). Align the Alert service updateDefinition operation to the same style.
  • Reword the wildcard requirements as provider obligations in the “If …, then …” conditional form instead of “the field shall support the wildcard”.
  • Fix a copy-paste in AggregationDefinition.description (“parameter” -> “aggregation”) and rename AggregationValueDetails.defId to definitionId, consistent with the monitorValue subscription key.

Regenerate api-nmf-mc and update the affected provider impls and the CTT Aggregation panel accordingly.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Give stopApp a grace-period timeout and move the shutdown guard off the App

An App is managed by the Supervisor, so escalation from a gentle stop to a forced kill belongs to the Supervisor, not to a self-destruct timer inside the App. The old AppShutdownGuard (a hardcoded 5 s System.exit(-1)) killed legitimate slow-but-graceful App shutdowns and was stricter than the Supervisor’s own patience.

  • Add a timeout (Duration, nullable) field to the stopApp operation. NULL means the App is never forcibly killed; a non-NULL value makes the Supervisor force-kill the App (-> KILLED) if it has not closed within the grace period. Plumbed through AppsLauncherManager.stopNMFAppGracefully, which on expiry marks the App kill-pending and kills the process.
  • Remove AppShutdownGuard from the App (NanoSatMOConnectorImpl).
  • Keep a shutdown watchdog for the top-level processes that have no parent to force-kill them: rename AppShutdownGuard to the generic ShutdownGuard, make its timeout configurable via the nmf.shutdown.guard.ms system property, and call it only from NanoSatMOSupervisor and NanoSatMOMonolithic.
  • Update all stopApp callers (Supervisor, NMFPackageManager, CLI, CTT) to pass a NULL timeout (gentle, unchanged behaviour).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add a broken-app testbed and non-nominal / broken-retrieval tests

Adds coverage for non-nominal MC retrieval and App shutdown behaviour.

  • New testbeds/broken-app-for-testbeds: a deliberately misbehaving NMF app (kept out of the SDK). Its parameter, action and aggregation fail on retrieval, each paired with a healthy control; shutdown.delay / shutdown.hang make its onClose block for a finite or effectively infinite time.
  • testbed-area-mc: BrokenBackend + BrokenRetrievalTest verify the MC service contract in-process (a failing backend surfaces as INVALID_RAW on getValue for parameters and aggregations, and as an execution failure for actions).
  • testbed-e2e: BrokenRetrievalTest exercises the same through the full stack, and AppLifecycleNonNominalTest checks that a slow-but-graceful shutdown completes cleanly (exit 0) while a hung App is force-killed by the Supervisor after the stopApp grace period (KILLED). AppHarness gains getParameterValues/getAggregationValues/awaitActionOutcome and a stop(awaitMs, Duration grace) overload.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Un-ignore testMonitorEventsOnStart

The MAL broker fix it was waiting on is present in the adopted mo-services-java v14.1, and the test now passes in the full e2e suite.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Key the docgen Maven cache by pom hash instead of a timestamp

The generate-docs workflow keyed its ~/.m2 cache on a per-run timestamp, so every push minted a brand-new cache entry instead of reusing one, churning through the repository’s Actions cache budget. Key it on the pom.xml hashes so a single cache is reused until dependencies change; restore-keys still provides a warm fallback. The Get Date step is retained for the artifact name.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Build the broken-app testbed fixture before the e2e job

The testbed-e2e job resolved broken-app-for-testbeds:nmfpack from ~/.m2, but nothing put it there: that module lives only in the testbeds reactor, which the root “mvn install” (which does install the sdk example-app nmfpacks) never builds. Install the broken-app nmfpack into the local repository before running the E2E testbed so its dependency resolves.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Complete the AppsLauncher COM objects diagram

The AppsLauncherObjects diagram only drew AppDetails. Add the AppStarted and AppStopped objects with related-arrow links to AppDetails, matching the service’s COM object model, and tighten the canvas height for the single row. Uses the existing static-SVG conventions already in the file.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Remove embedded SVG diagrams from the MO spec XML

The service XML files are the specification and should not carry graphical SVG: a hand-maintained diagram also drifts out of sync with the COM objects it depicts. Remove all mal:diagram blocks (PackageManagementObjects, AppsLauncherObjects, GPSObjects) and the now-unused xmlns:svg namespace declarations from area052/053/054. No code impact: the API generator and doc tooling do not use these diagrams.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add a deploy-on-remote profile to transfer the barebone filesystem

Adds a Maven profile that uploads the generated Space File System of the barebone mission to a remote machine over scp, following the wagon-maven-plugin pattern used by the raspberry-pi mission.

The profile is self-contained: it declares both the generate-filesystem goal (package phase) and the wagon upload (install phase), so a single “mvn install -Pdeploy-on-remote” generates the filesystem and then transfers it, without depending on the generate-filesystem profile also being active. The generation execution is defined once in pluginManagement and reused by both profiles.

Also:

  • the scp target is a configurable property (deploy.remote.url), overridable with -Ddeploy.remote.url=scp://user@host/;
  • the wagon-ssh provider is scoped to the profile so normal builds never resolve it;
  • corrected the out.folder.output property to “space-filesystem” (no hyphen) so the upload’s fromDir matches where the NMF 5.0 plugin actually writes.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Rename the nmf-services-impl module display name

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Implement the docker-containers app isolation mode

Adds AppsLauncherManagerDocker, the runtime for the docker-containers isolation mode that was already declared in AppsIsolationMode and selectable in the generate-filesystem plugin. The Supervisor keeps managing the app lifecycle; it just launches each app inside its own container:

  • assembleCommand builds a “docker run –rm –name nmf-app- –network host -v : -w /bin/sh -c ./start_app.sh”. The whole NMF home is mounted at the same path so the app’s start script finds the shared jars and its log directory unchanged.
  • the central directory URI is passed through JAVA_OPTS, as for bubblewrap.
  • killAppProcess is overridden to “docker rm -f” the container, since killing the docker run client alone does not reliably stop it; a graceful stop needs no override.
  • the base image and network are configurable via the esa.mo.nmf.packagemanager.docker.image / .network system properties (defaults eclipse-temurin:21-jre and host).

Wires the isDockerContainers() branch into AppsLauncherProviderServiceImpl and adds a unit test that pins the assembled docker run command (no Docker daemon needed).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Use short exception names in AppsLauncherManager

The multi-catch and throws clauses spelled out fully-qualified exception names inline, which made them hard to read. Import UnknownException and DuplicateException (InvalidArgumentException was already imported) and use the short names. No behavioural change.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add a Docker image build for the barebone Space File System

Add a Dockerfile (and .dockerignore) that packages the generated Space File System into a slim eclipse-temurin runtime image, plus a docker Maven profile that generates the filesystem and builds the image in one step. Document the Docker and remote-deploy workflows in the README.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix Duplicate error when archiving CommandOutput chunks

publishOutput passed commandId as the CommandOutput COM object’s instance id, so every output chunk beyond the first collided with the same id and the archive store threw Duplicate. Pass commandId as the ‘related’ link instead and let the archive auto-assign a fresh instance id per chunk, which also records each output’s parent Command.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Align bootloader log format with the Supervisor’s java.util.logging

Make every Boot Report line start with a timestamp followed by a BOOTLOADER source tag, so the bootloader output lines up with the Supervisor’s java.util.logging lines. Replace the “=== BOOT REPORT START ===” marker with a separator plus a “Boot started at:” line, drop the misleading “=== BOOT REPORT END ===” marker (the bootloader keeps running to supervise the JVM), and keep the nominal confirmation entry in the report file only (silent on the console). Retarget BootloaderTest to the new start and confirmation entries.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add a nominal ActionTest to testbed-area-mc

Cover the healthy Action path: a consumer triggers an action, the provider forwards it to the backend’s actionArrived handler, and the execution is reported as successful over monitorExecution. Complements BrokenRetrievalTest, which covers the failure path.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix flaky e2e action test by polling for the action registration

awaitActionOutcome called listDefinition once, right after the app appeared in the Directory. But the app registers its action definitions later, in initialRegistrations(), so listDefinition could return the MAL UNKNOWN error and fail the test intermittently. Resolve the definition id by polling listDefinition until it appears (retrying only on UNKNOWN, rethrowing any other error) within the timeout.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Update release notes for the Bootloader and Docker deployment

Refresh the Version 5.0 date and add entries for the NMF Bootloader and the Docker-based deployment path.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix CTT crashes rendering and sorting MO objects in tables
  • FieldsHandler: pick the primitive (non-String) constructor when building a default boxed value, instead of assuming getDeclaredConstructors()[0] (Integer(String) was selected, causing an argument type mismatch).
  • AggregationAddModify: store the definition name as a String in the table instead of the raw Identifier, matching the other panels.
  • PackageManagementTablePanel: declare the package-name column as Object (it holds an Identifier), so the row sorter compares via toString() instead of casting to String and throwing a ClassCastException.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Key the CI Maven cache on the pom hash instead of the week

The testbeds workflow rotated the Maven cache by ISO week, but actions/cache keys are immutable (written only on a miss), so a change within the same week restored a stale cache and could not re-save.

Key every cache on hashFiles(‘**/pom.xml’) with a restore-keys fallback so it rotates when the poms change (version bumps, dependencies) and warms otherwise. Move the build jobs’ cache step before the install so they restore dependencies instead of always cold-downloading. Testbed jobs rebuild the framework themselves, so this is purely a dependency cache and needs no per-commit key. Also removes the now-unused Get Date steps (kept only the timestamp in the performance jobs).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Bump upload-artifact to v5 to run on Node.js 24

The performance jobs still used actions/upload-artifact@v4, which targets the deprecated Node.js 20 runtime. Bump it to v5 (Node.js 24), matching the other actions already on v5.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Increase performance testbed Supervisor startup timeout

CLIPerformanceTest flaked on CI with “Supervisor did not become ready within 3 seconds”: the Supervisor’s own initialisation (archive backend, fast classes, service startup) routinely takes several seconds and a loaded runner exceeds 3s. Raise STARTUP_TIMEOUT_SECONDS to 30 and SHUTDOWN_TIMEOUT_SECONDS to 10, giving generous margin (the e2e harness uses 10s).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Drop deprecated getSecurityManager() from thread factories

System.getSecurityManager() is deprecated for removal (JEP 411) and always returns null on Java 24+, so the SecurityManager branch of the copied DefaultThreadFactory boilerplate is dead. Use Thread.currentThread().getThreadGroup() directly, which is what the JDK now does. No behavioral change.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Update the MO parent to 14.1

Point the build at the released int.esa.ccsds.mo:parent:14.1, now available on Maven Central.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Update the 5.0 release notes

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Trim MemoryMCAdapter to RAM and swap parameters

Removes the EDAC error counters, PSI memory pressure, and page-fault parameters (and their /sys and /proc/vmstat helpers) to simplify the default Supervisor memory adapter. Updates the supervisor docs to match.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Make AppLifecycleNominalTest isolation-safe

Two test-only fixes so every method passes on its own as well as in the full class:

  • The self-exit tests created a local “benchmark” AppHarness that was never torn down. A lingering instance (e.g. a self-exit that did not reap in time) left the app registered as running, so the sibling test’s runApp was rejected with an INVALID (already-running) error. Track the harness in a field and force-stop it in @After.

  • testAppStoppedInArchive asserted records.get(0) (the oldest AppStopped record) was STOPPED, but the Supervisor’s COM archive persists across runs and accumulates KILLED records from other tests. Select the most recent record by archive timestamp instead.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Remove the unused getValueWithCustomValidityState hook

This ParameterStatusListener method was a custom-validity extension point in the parameter-sampling path (ParameterManager.generateNewParameterValue): a non-null return would bypass the standard conversion/validity handling. Every implementation in the codebase only returned null, so the hook was dead. Drop it from the interface, inline the call site to the standard path, and remove all no-op overrides.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Harden restoreParameterValuesFromArchive

Clean up the parameter restore-on-restart path in the annotation adapter:

  • Use the parameterMapping key directly as the parameter definition id instead of re-resolving it via listDefinition().get(0). This drops a service round-trip per parameter and removes the unguarded get(0) that could throw IndexOutOfBoundsException.
  • Catch failures per-parameter (broad catch) so a missing value, type mismatch, or archive error on one parameter can no longer escape the loop and abort app startup.
  • Replace the misleading “assume newest” comment with the actual reason (sortOrder=false sorts by timestamp descending), and lower the per-parameter miss from SEVERE to WARNING.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Always construct a valid MO domain at startup

The MO domain is built once from the OrganizationName/MissionName/MOappName System properties. The Supervisor only set MOappName (and suppresses file loading), and an App run from an IDE has no provider.properties, so the domain degraded to the “domainNotFoundInPropertiesFile” placeholder.

Add MissionConfiguration.ensureDomainIdentity(): a layered, non-destructive resolver that sets OrganizationName/MissionName before the domain is first constructed. Precedence: an already-set System property (-D or a loaded provider.properties) wins, else etc/mission.properties, else built-in defaults (nmf/dev). Because a default always exists, every properties file is optional and the domain is always valid. Wired into the Connector, Supervisor, and Monolithic startup paths.

Also lowercase organizationAbbreviation ESA -> esa in the mission configs so the Supervisor domain (from mission.properties) matches the Apps’ esa segment.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add NMF core baseline packages and decouple ship/activate

Enable shipping an NMF core software baseline as an installable package, keeping “ship” (install), “activate” (setPrimaryBaseline action) and “fall back” (bootloader) as separate, safe steps.

Generator:

  • MetadataNMF and an NMFPackageBuilder branch place the framework JARs under jars-nmf//, so a new core baseline installs beside the existing one (both kept for fallback).
  • New generate-nmf-core-package goal packages the generate-filesystem output into an nmf-.nmfpackage.

Install / activate:

  • Installing a baseline component only stages its files (regenerates the SHA256SUMS); it no longer rotates the baseline. Activation is the validated setPrimaryBaseline action, which now writes only the primary.
  • upgrade() is rejected for baseline components (nmf/mission/java): they are installed and switched, never replaced in place.
  • Re-installing an already-installed final version is rejected; SNAPSHOT versions are not final and may always be overridden (isFinalVersionInstalled, distinct from isPackageInstalled).

Fallback:

  • The bootloader promotes the just-booted, confirmed baseline to secondary (last known-good). This is a promotion of the running baseline, not a rotation of the previous primary, so re-pointing the primary several times before a reboot never pushes an un-booted version into secondary.

Tests: BootloaderPromotionTest (promotion), NMFPackageLifecycleTest test2b (SNAPSHOT re-install succeeds). Full testbed-e2e suite green.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Add a commanded Supervisor restart to apply baselines on-board

A live JVM cannot reload its own framework classes, so a newly activated NMF core baseline only takes effect on the next boot. Add a generic restart that re-boots the process through the bootloader.

  • Deployment.EXIT_RESTART (90): a dedicated exit code, distinct from a clean shutdown (0) and a crash (any other non-zero code).
  • bootloader.restart action: acknowledges, then exits with the restart code after a short grace period so the response reaches ground. The exit runs the shutdown hook (graceful App stop). It is generic and carries no update-specific logic.
  • start_supervisor.sh: on exit 90 it re-executes the Nominal Sequence in place and boots the current primary baseline. Following a confirmed boot, this is a fresh attempt with the full confirmation window and fallback, not a counted boot failure.

Applying a core update is now install -> setPrimaryBaseline -> restart.

Docs: document the commanded restart (REC.06 + design section) and fix the now-stale secondary-baseline description to the bootloader promotion model.

Test: BootloaderRestartTest drives the action and asserts the bootloader re-executes and boots again. Full testbed-e2e suite green.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Soak-gate the bootloader secondary promotion

Confirmation proves the Supervisor’s services started, not that the baseline is stable, so promoting the running baseline into the secondary immediately means a baseline that confirms and then crashes would replace the last known-good and defeat the fallback.

The bootloader now records the boot as confirmed at once (fallback state reset unchanged), but promotes the running baseline to secondary only after it has stayed up for PromotionSoakTime (config knob promotion-soak-s, default 60s). If the Supervisor exits during the soak, the secondary is left unchanged. When the soak starts, the Boot Report logs which baseline will be promoted and when. Skips instantly when there is nothing to promote (secondary booted, or already matches the running baseline).

  • start_supervisor.sh: promote_after_soak + promotion-soak-s config knob.
  • BootloaderGenerator: emit promotion-soak-s=60 in config.properties.
  • BootloaderPromotionTest: short soak override (snapshot/restore config).
  • Docs: REC.04 soak wording + PromotionSoakTime parameter.

Full testbed-e2e suite green.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fill the CTT Published Parameter Values tab first-come-first-served

The tab placed each parameter in a fixed grid cell derived from its object instance id. With the Supervisor’s larger default parameter set, those ids fall past the grid, so the index-in-bounds guard never fired and the tab stayed blank.

Assign each parameter a display slot in the order its first update arrives instead of by its id, remembering it so the parameter always redraws in the same cell. Slot 0 stays reserved for the header; parameters fill the rest of the grid and further new ones are dropped once it is full. Each cell still shows “(objId) name” to identify the parameter.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Report attitude quaternion as invalid until a value is received

The supervisor’s attitudeQuat A/B/C/D parameters returned a cached float initialised to 0, so a getValue before any ADCS attitude update returned a misleading zero instead of signalling that no value had been obtained.

Make the fields boxed Float initialised to null and return null from onGetValue while unset; the MC framework maps a null raw value to the INVALID_RAW validity state (as the magnetometer already relies on). The fields are volatile since they are written on the MAL notify thread and read on the MC request thread.

(The separate root cause - AutonomousADCS.enableMonitoring never being called, so the monitoring generation never starts - is still to be fixed.)

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix the ADCS attitude publisher dying silently on its first update

The update header keys wrongly included a NamedValueList, which is not an Attribute; the resulting ClassCastException escaped the fixed-rate publish task and silently cancelled all future runs, so no attitude ever reached the Supervisor cache. Publish with an empty key list like the other keyless publishers, guard the task against any escaping Throwable, and enable generation independently of the subscription registration.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

  • Bump the 5.0 release date to 20 July 2026

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix stale Javadoc references breaking javadoc:javadoc

The doclet treats bad @param/@return/@link references as hard errors, so these failed the Javadoc build:

  • ParameterManager: @param named a nonexistent parameter, and two @return tags remained on methods that are now void
  • DefaultSupervisorAdapters: @link pointed at a no-arg create() that does not exist; the method takes an NMFProvider

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Fix flaky AppLifecycle self-exit tests: dispatch actions race-tolerantly

launchAppAction went through GroundMOAdapterImpl.launchAction, which does a one-shot listDefinition and swallows any failure (logs SEVERE and returns). When the app was registered in the Directory but had not yet finished initialRegistrations(), listDefinition threw UnknownException, the action was silently never dispatched, and the test failed 10 s later with the misleading “OS process must be gone after self-exit”.

Dispatch directly against the app’s ActionStub, resolving the definition id via the existing race-tolerant resolveActionDefId helper. This closes the registration-window race and fails fast with the real cause if the action never registers.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Skip the SNAPSHOT-reinstall testbed assertion on release builds

test2b_ReinstallSnapshotSucceeds exercises SNAPSHOT-only behaviour (a SNAPSHOT package is not final and can be re-installed). It hard-asserted that precondition, so it failed outright on a non-SNAPSHOT build instead of being skipped. Use Assume.assumeTrue so it runs during SNAPSHOT development and is skipped on release builds, where re-installing a final package is rejected (covered by test4).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Remove obsolete Eclipse .launch configs and update docs

The three sdk/launch-configs/*.launch files targeted the removed sdk-execution-environment layout (and SimClient.launch carried a hardcoded personal path and a since-renamed simulator module). Delete them and point the referencing docs (ides.rst, simulator.rst, sdk/README.md) at the playground scripts run_Supervisor.sh / run_CTT.sh / run_Simulator_Client.sh.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Bump version from 5.0-SNAPSHOT to 5.0

Update the Maven version across all modules (the esa.nmf.version property and every module/parent reference), plus the version-tied references in CLAUDE.md, the Sphinx release, docs, and testbed comments.

Also make the start_supervisor.sh example comment version-agnostic (prints “x.y”), since that script deliberately carries no version and resolves it at runtime from the bootloader baseline properties.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Use a version-agnostic example in findPackageByPrefix javadoc

The prefix-resolution example does not depend on a specific version, so show “benchmark-x.y.nmfpack” instead of a concrete version.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Ignore -sources/-javadoc jars when finding the app jar to package

findAppJarInFolder globbed every jar in target/ and failed with “too many jars” once the release profile added the -sources and -javadoc artifacts alongside the application jar. Skip those auxiliary artifacts (and -tests) so mvn deploy -P release can package the app; the single-jar and -jar-with-dependencies fat-jar paths are unchanged.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Isolate testbed-area-com forks and bound testbed CI jobs

DirectoryLookupTest intermittently hung in CI: the COM-area tests each stand up full MAL providers/consumers on the RMI transport (registry on port 1024), and surefire’s single reused fork let that process-global transport state leak between classes. When DirectoryLookupTest ran after the others (CI’s alphabetical order), its synchronous, un-timed consumer setup occasionally blocked forever. With no surefire or job timeout, the run hung until GitHub’s 6-hour limit.

Run each area-com test class in its own JVM (reuseForks=false) to remove the shared-transport trigger, add a forkedProcessTimeoutInSeconds guard, and set timeout-minutes on every testbeds job so a hang can never stall a runner indefinitely again.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Publish to Maven Central via the central-publishing plugin

The release deploy inherited from the MO parent uses nexus-staging, whose deferred upload fires on the last reactor module. In NMF’s single-root layout the aggregator root builds first and the last module (sdk) skips staging, so the upload never happened and nothing reached Central.

Add a release-profile override that neutralises nexus-staging, disables the stock deploy, and publishes the whole reactor as one Central Portal bundle via central-publishing-maven-plugin (extensions=true), matching the modern Sonatype Portal flow used by projects such as WildFly. autoPublish=false / waitUntil=validated uploads and validates the bundle but leaves the final publish for a manual review at central.sonatype.com.

Exclude three heavyweight, non-library artifacts from the bundle via per-module skipPublishing: camera-acquisitor-system-ground, orekit-resources, and cubesat-spacecraft-simulator.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

  • Bump the 5.0 release date to 21 July 2026

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com


Co-authored-by: Claude Sonnet 4.6 noreply@anthropic.com

22天前1128次提交

esa logo

NanoSat MO Framework

Maven Central Build Status

The NanoSat MO Framework is a software framework for small satellites based on CCSDS Mission Operations services.

It introduces the concept of apps in space that can be started and stopped from ground. Apps can retrieve data from the platform through a set of well-defined MO services. Many possibilities for extensions are available due to its modular and flexible design approach which is not limited to the space segment but extends down to ground by providing all the building blocks for a complete and free end-to-end solution.

A Software Development Kit (SDK) is available in order to facilitate the development with the NanoSat MO Framework.

Wikipedia page: https://en.wikipedia.org/wiki/NanoSat_MO_Framework

Documentation: https://nanosat-mo-framework.readthedocs.io/en/latest/

Interfaces of the services: https://dmarszk.github.io/MOWebViewer4NMF/

Research Work Dissertation: https://www.researchgate.net/publication/321825076

The research was carried by Graz University of Technology in partnership with the European Space Agency.

Release

The latest NMF SDK release tag can be downloaded in Releases. However, the currently recommended distribution channel is directly from Git repository.

Building Prerequisites

  1. Install Java SDK 11 (will work with higher SDKs but 11 is the recommended)
    sudo apt-get install openjdk-11-jdk
  2. Install Apache Maven
    sudo apt-get install maven

Building Instructions

  1. Clone this repository

    git clone https://github.com/esa/nanosat-mo-framework.git
  2. Build the cloned NanoSat MO Framework project:

    mvn clean install

Note that the errors about missing module descriptors during Javadoc generation are to be expected and non-breaking.

In order to produce independently runnable Java executables (JAR artifacts with dependencies - equivalent of statically linked executables), use mvn install -P assembly-with-dependencies

Getting Started

SDK and examples

More documentation about code examples, SDK packaging and usage is available under sdk directory.

Logging

This project uses the default Java logger (java.util.Logger) to generate log messages. The verbosity of these log messages can be changed by configuring the logging.properties file inside the Supervisor’s working directory.

Source Code

The source code of the NanoSat MO Framework can be found on GitHub.

Bugs Reporting

Bug Reports can be submitted on: Issues

Or directly in the respective source code repository.

License

The NanoSat MO Framework is licensed under:

European Space Agency Public License (ESA-PL) Weak Copyleft – v2.4.

关于

ESA 基于 CCSDS MO 服务标准的小卫星在轨应用框架,提供标准星地交互与应用部署能力。镜像收录自 https://github.com/esa/nanosat-mo-framework,未检测到 LICENSE 文件

146.2 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号