Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9b538c1
fix: repair dic preprocess interactions and alignment
Pluze Aug 3, 2026
777c7b9
feat: simplify session diagnostics and automatic export
Pluze Aug 3, 2026
9ee6896
fix: clarify validation and launcher labels
Pluze Aug 3, 2026
203838f
fix: restore electrochem batch imports
Pluze Aug 3, 2026
dde1d66
test: configure focused specs across apps
Pluze Aug 3, 2026
becd0a6
chore: consolidate pending sdk version
Pluze Aug 3, 2026
deb129a
fix: improve dic registration feedback
Pluze Aug 3, 2026
d057a97
feat: add explicit sensitive diagnostic export
Pluze Aug 3, 2026
c27ef9e
fix: unify app file selection behavior
Pluze Aug 3, 2026
f790bd6
feat: retain complete session diagnostics
Pluze Aug 3, 2026
b8bd37c
chore: enforce squash pr history coherence
Pluze Aug 3, 2026
bfdd8d7
fix: strengthen dic rigid registration
Pluze Aug 3, 2026
ec96920
fix: highlight session log rows
Pluze Aug 3, 2026
2a8565c
fix: persist marker edits and repair gait preview
Pluze Aug 3, 2026
6dc713f
fix: stabilize curvature point editing
Pluze Aug 3, 2026
e398e9a
fix: make diagnostic state export optional
Pluze Aug 3, 2026
d2ab49e
feat: add compact diagnostic state bundles
Pluze Aug 3, 2026
4d21903
feat: harden app busy feedback
Pluze Aug 3, 2026
907db7d
refactor: layer app sdk internals
Pluze Aug 3, 2026
4d75eba
refactor: group app diagnostics internals
Pluze Aug 3, 2026
c21bb2d
refactor: group app runtime stores
Pluze Aug 3, 2026
238129f
refactor: isolate app native internals
Pluze Aug 3, 2026
9dd357f
refactor: separate app contract and runtime internals
Pluze Aug 3, 2026
0a2e047
refactor: split launcher internal responsibilities
Pluze Aug 3, 2026
73e66fc
refactor: split runtime kernel workflows
Pluze Aug 3, 2026
684414b
docs: clarify app internal dependency edges
Pluze Aug 3, 2026
4f1d832
test: isolate app specs from sdk internals
Pluze Aug 3, 2026
6701b73
chore: prepare squash pr inventory
Pluze Aug 3, 2026
4072fb4
test: update definition catalog expectations
Pluze Aug 3, 2026
27bb5cf
test: complete gait preview fixture
Pluze Aug 3, 2026
e24a266
fix: stabilize cross-platform pr validation
Pluze Aug 4, 2026
d6a9442
fix: use native equal data aspect
Pluze Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion +labkit/+app/+dialog/Choice.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

methods
function obj = Choice(value, varargin)
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.dialog.Choice", "Cancelled", varargin{:});
cancelled = false;
if isfield(options, "Cancelled")
Expand Down
2 changes: 1 addition & 1 deletion +labkit/+app/+event/IntervalScroll.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

methods
function obj = IntervalScroll(varargin)
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.event.IntervalScroll", ...
["Anchor", "Count"], varargin{:});
for name = ["Anchor", "Count"]
Expand Down
2 changes: 1 addition & 1 deletion +labkit/+app/+event/ListSelection.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

methods
function obj = ListSelection(varargin)
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.event.ListSelection", ["Ids", "Indices"], varargin{:});
obj.Ids = ids(optionValue(options, "Ids", strings(1, 0)));
obj.Indices = indices( ...
Expand Down
2 changes: 1 addition & 1 deletion +labkit/+app/+event/TableCellEdit.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
function obj = TableCellEdit(varargin)
names = ["RowId", "RowIndex", "ColumnId", "ColumnIndex", ...
"PreviousValue", "NewValue", "Data"];
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.event.TableCellEdit", names, varargin{:});
for name = ["RowIndex", "ColumnIndex", ...
"PreviousValue", "NewValue"]
Expand Down
8 changes: 6 additions & 2 deletions +labkit/+app/+interaction/anchorPath.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
% Description:
% Creates the semantic declaration for a managed multi-anchor path editor;
% the runtime owns native graphics, viewport preservation, and dispatch.
% On an open path, a point placed beyond the visible start is prepended, a
% point beyond the visible end is appended, and all other points are inserted
% after the nearest visible curve segment. This ordering is independent of
% the current axes zoom.
%
% Inputs:
% id - Unique MATLAB identifier for this interaction.
Expand Down Expand Up @@ -34,7 +38,7 @@
end

function spec = makeSpec(kind, id, callback, names, varargin)
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction." + kind, names, varargin{:});
spec = labkit.app.internal.InteractionSpec(kind, id, callback, options);
spec = labkit.app.internal.interaction.InteractionSpec(kind, id, callback, options);
end
4 changes: 2 additions & 2 deletions +labkit/+app/+interaction/interval.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
%
% See also labkit.app.layout.plotArea,
% labkit.app.event.IntervalScroll
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction.interval", ...
["Axis", "Style", "Instruction", "ViewportPolicy", "OnScrolled"], ...
varargin{:});
spec = labkit.app.internal.InteractionSpec("interval",id,onChanged,options);
spec = labkit.app.internal.interaction.InteractionSpec("interval",id,onChanged,options);
end
4 changes: 2 additions & 2 deletions +labkit/+app/+interaction/pairedAnchors.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
% spec = labkit.app.interaction.pairedAnchors("matches",@changeMatches);
%
% See also labkit.app.layout.plotArea
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction.pairedAnchors", ...
["Axes", "Style", "Instruction", "ViewportPolicy"], varargin{:});
if ~isfield(options, "Axes")
error("labkit:app:contract:UnknownArgument", ...
"labkit.app.interaction.pairedAnchors requires Axes.");
end
spec = labkit.app.internal.InteractionSpec( ...
spec = labkit.app.internal.interaction.InteractionSpec( ...
"pairedAnchors", id, onChanged, options);
end
4 changes: 2 additions & 2 deletions +labkit/+app/+interaction/pointSlots.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
% spec = labkit.app.interaction.pointSlots("markers",@changeMarkers);
%
% See also labkit.app.layout.plotArea
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction.pointSlots", ...
["Axis", "Style", "Instruction", "ViewportPolicy"], varargin{:});
spec = labkit.app.internal.InteractionSpec("pointSlots",id,onChanged,options);
spec = labkit.app.internal.interaction.InteractionSpec("pointSlots",id,onChanged,options);
end
4 changes: 2 additions & 2 deletions +labkit/+app/+interaction/rectangle.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
% spec = labkit.app.interaction.rectangle("crop",@moveCrop);
%
% See also labkit.app.layout.plotArea
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction.rectangle", ...
["Axis", "Style", "Instruction", "ViewportPolicy", ...
"OnBackgroundPressed"], varargin{:});
spec = labkit.app.internal.InteractionSpec("rectangle",id,onChanged,options);
spec = labkit.app.internal.interaction.InteractionSpec("rectangle",id,onChanged,options);
end
4 changes: 2 additions & 2 deletions +labkit/+app/+interaction/regionSelection.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
% OnBackgroundPressed=@measurePoint);
%
% See also labkit.app.layout.plotArea
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction.regionSelection", ...
["Axis", "Style", "Instruction", "ViewportPolicy", ...
"OnBackgroundPressed"], varargin{:});
spec = labkit.app.internal.InteractionSpec( ...
spec = labkit.app.internal.interaction.InteractionSpec( ...
"regionSelection",id,onSelected,options);
end
4 changes: 2 additions & 2 deletions +labkit/+app/+interaction/scaleReference.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
% spec = labkit.app.interaction.scaleReference("scale",@changeScale);
%
% See also labkit.app.layout.plotArea
options = labkit.app.internal.OptionParser.parse( ...
options = labkit.app.internal.contract.OptionParser.parse( ...
"labkit.app.interaction.scaleReference", ...
["Axis", "Style", "Instruction", "ViewportPolicy"], varargin{:});
spec = labkit.app.internal.InteractionSpec( ...
spec = labkit.app.internal.interaction.InteractionSpec( ...
"scaleReference",id,onChanged,options);
end
63 changes: 63 additions & 0 deletions +labkit/+app/+internal/+artifact/Store.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
classdef (Hidden, Sealed) Store
% Own App-specific artifact naming and repository scratch destinations.
% Caller: RuntimeKernel. Inputs are domain-neutral artifact tokens; output
% paths always remain below the checkout's ignored artifacts directory.

properties (Access = private)
AppId (1, 1) string
end

methods
function obj = Store(appId)
obj.AppId = artifactToken(appId, "App ID");
end

function destination = destination(obj, category, stem, extension)
category = artifactToken(category, "category");
filename = obj.filename(stem, extension);
folder = artifactFolder(category);
if exist(char(folder), "dir") ~= 7
[created, message] = mkdir(char(folder));
if ~created
error("labkit:app:runtime:ArtifactWriteFailed", ...
"Could not create the LabKit artifacts folder: %s", ...
message);
end
end
destination = fullfile(folder, filename);
end

function filename = filename(obj, stem, extension)
stem = artifactToken(stem, "stem");
extension = string(extension);
if ~isscalar(extension) || ...
isempty(regexp(char(extension), ...
'^\.[a-z0-9]+$', "once"))
error("labkit:app:runtime:InvariantFailure", ...
"Artifact extension must be a lowercase file extension.");
end
timestamp = string(datetime("now", TimeZone="UTC", ...
Format="yyyyMMdd-HHmmss"));
nonce = extractBefore( ...
string(java.util.UUID.randomUUID()), 9);
filename = "labkit-" + stem + "-" + obj.AppId + "-" + ...
timestamp + "-" + nonce + extension;
end
end
end

function folder = artifactFolder(category)
versionPath = string(which("labkit.app.version"));
root = string(fileparts(fileparts(fileparts(versionPath))));
folder = fullfile(root, "artifacts", category);
end

function value = artifactToken(value, label)
value = lower(strip(string(value)));
value = regexprep(value, "[^a-z0-9]+", "-");
value = regexprep(value, "(^-+|-+$)", "");
if ~isscalar(value) || strlength(value) == 0
error("labkit:app:runtime:InvariantFailure", ...
"Artifact %s must contain letters or digits.", label);
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

methods (Access = ?labkit.app.Definition)
function obj = CompiledDefinition(layout, startCallback)
if ~isa(layout, "labkit.app.internal.LayoutNode") || ...
if ~isa(layout, "labkit.app.internal.contract.LayoutNode") || ...
layout.Kind ~= "workbench"
error("labkit:app:contract:InvalidValue", ...
"Definition Workbench must be a workbench Layout value.");
end
onStart = [];
if ~isempty(startCallback)
onStart = labkit.app.internal.SignalBinding( ...
onStart = labkit.app.internal.contract.SignalBinding( ...
"application", "started", startCallback);
end
nodes = layout.flattenForCompiler();
Expand Down
Loading