diff --git a/.agents/migration_guide.md b/.agents/migration_guide.md index d25a7c08e..8fb101101 100644 --- a/.agents/migration_guide.md +++ b/.agents/migration_guide.md @@ -36,18 +36,26 @@ classes. owner-first specs, parameterized App conformance, `labkittest`, and the narrow `+testfixtures` package. The cutover deleted 28,840 test lines and added 5,524; most deletion is test code rather than product code. -- Headless and hidden-GUI profiles select `Env:headless` and - `Env:hidden-gui` respectively. `AppIsolationConformanceSpec` is tagged - `Env:isolated-process`, but no stable Build task or CI job selects that - environment. Current green CI is therefore not isolation evidence. -- The isolation child script stops after its first App exception. It must - continue through all Apps and return an aggregate failure report. -- `changedFast` is exact for mapped App roles, but an unmapped, Build, - framework, or policy path widens only to headless evidence. Its fallback - must include every affected automated environment, rather than silently - omitting hidden-GUI or isolated-process evidence. -- `ManualChecks` is present in a compiled plan but is always empty. Empty - metadata must not be described as an evidence boundary. +- Build and CI now select `Env:path-isolated` on Linux, macOS, and Windows. + Its catalog-selected aggregate test resets paths before every public App, + then returns a complete failure report. This retains the App boundary without + requiring a second concurrent named-user license checkout. +- `changedFast` now widens unmapped, Build, framework, and policy paths to + every automated environment: headless, hidden-GUI, and path-isolated. +- `AppSmokeConformanceSpec` now verifies every compiled layout target that + must materialize as exactly one native semantic component. Interaction + declarations remain view targets but correctly share their owning axes; they + are not false component IDs. This restores the common structural assertion + formerly duplicated across the App GUI layout wrappers. +- Every production `apps/**/*.m` and `+labkit/**/*.m` source now has an + explicit `locate` result. The guardrail includes thin public launchers, which + select the same definition, hidden-GUI, and path-isolated closure as their + App package. The `labkit.contract` facade has direct requirement, version, + incompatibility, and assertion evidence under `framework/contract`. +- `ManualChecks` passed its bounded trial: a mapped `buildLayout` path emits + an owner-derived instruction through `explain`, `plan.json`, and `run`, while + source/result/scientific paths remain empty and manual work never passes an + automated plan. #### High-value App audit @@ -59,34 +67,38 @@ GUI workflow is not considered covered by a launch smoke test. | App | Current high-value evidence | Parity disposition | | --- | --- | --- | -| DIC Postprocess | strain domain, masks, overlays, source/result/presentation | Split: restore one bounded load-overlay-summary GUI workflow; retain source/export edge cases after direct parity check. | -| DIC Preprocess | masks, crop geometry, alignment, history, source/result/project/presentation | Split: restore semantic layout plus pair/alignment/crop workflow proof. | -| Chrono Overlay | pulse alignment, export interpolation, presentation | Split: restore plot/export/restore workflow proof. | -| CIC | core metrics, area/window policy, schema and summary | Gap: nominal-current branch, baseline selection/source, onset/access metrics, total charge, batch recompute, and workflow must be restored as owner specs. | -| CSC | cycle charge, modes/errors, CSV schema, presentation | Split: audit the retained edge-cycle/export branches; restore compare-and-plot workflow proof. | -| EIS | impedance mapping, source summary, result schema, presentation | Split: restore file-load/layout proof. | -| VT Resistance | scientific calculation including batch recompute, result schema, presentation | Split: restore layout/export/restore and redraw lifecycle proof. | -| Gait Analysis | segmentation, timing roles, project migration, CSV result, presentation | Split: preserve producer-reader compatibility, rejection branches, and one navigation/export/restore workflow proof. | -| Batch Crop | core crop geometry, physical size, manifest and overwrite policy | Gap: rotated/padded-crop policies, duplicate task handling, preview viewport/ROI lifecycle, and workflow export require direct evidence. | -| Curvature | circle/length science, migration, result schema, source/presentation | Split: restore invalid-curve and task-fingerprint branches plus fit-and-export workflow proof. | -| FLIR Thermal | extrema, ROI measurement, project/result/source/presentation | Split: restore raw fallback, correction/default warnings, shared range bounds, and display/export workflow proof. | -| Focus Stack | fusion, registration, project/result/source/presentation | Split: restore invalid-input and file-panel branches plus load/run workflow proof. | -| Image Enhance | basic enhancement, white balance, source/result/presentation | Gap: white-ROI, subject-preserving enhancement, tool availability, preview scaling, and workflow export evidence. | -| Image Match | white-balance and tone matching, source/result/project/presentation | Split: restore protected/Lab/histogram modes, reference separation, and workflow export proof. | -| Video Marker | connection order, coarse tracking, project/result/source/presentation | Gap: annotations, legacy import, subpixel/deterministic/cache tracking, toolbox parity, and marking/prediction/export workflow. | -| Figure Studio | style, overlay order, source limits, project/presentation | Gap: composite FIG import/export, canvas/title/log-axis edge cases, source handoff, and interactive preview/export workflows. | -| Nerve Response Analysis | train detection, roles, CAP metrics, migration, source/result/presentation | Split: restore legacy session-input branch and analysis workflow proof. | -| Response Review Stats | CSV parsing, aligned metrics, migration, result/presentation | Split: restore metrics/export workflow proof. | -| RHS Preview | role assignment, timing, migration, result/source/presentation | Split: restore filter discovery and preview workflow proof. | -| T-test Wizard | input table, Welch/pooled/paired/error statistics, result schema | Gap: project migration, UI selection semantics, and compare/plot/export workflow. | -| ECG Print | input controls, signal products, migration, result/presentation | Split: restore full load/analyze/plot workflow and standalone export boundary. | - -Repository guardrails are a separate parity inventory: version, dependency, -documentation, release, package-boundary, sensitive-data, and launcher rules -were deleted with no executable successor found. Each old guardrail must be -classified as retained elsewhere, rewritten as public-behavior evidence, or -explicitly retired with rationale; restoring private implementation-text scans -is not acceptable. +| DIC Postprocess | strain domain, finite ROI and edge trim, overlay generation, source/result/presentation, bounded load/generate/display/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| DIC Preprocess | masks, crop geometry, toolbox-free alignment, history, source/result/project/presentation, bounded pair/alignment/crop/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Chrono Overlay | definition/version metadata, project migration, pulse alignment, export interpolation, presentation, generic semantic layout, bounded load/plot/export/restore workflow | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| CIC | core metrics, baseline/source and access policies, nominal current, batch recompute, result schema, success/failed summary, display-unit fallback, stable plot requests, generic semantic layout, bounded workflow | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| CSC | full/cathodic/anodic charge branches, zero-crossing subdivision, invalid statuses, all-cycle and voltage/current CSV export, edge-cycle filtering, presentation, generic semantic layout, bounded compare-and-plot workflow | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| EIS | impedance mapping, source summary, result schema, presentation, generic semantic layout, bounded load/plot/export/restore workflow | Covered: direct source/result/plot specifications plus the hidden-GUI workflow replace the legacy export/layout wrappers. | +| VT Resistance | steady/center-window and raw-voltage policies, batch recompute, result schema/failed rows/CSV, presentation, generic semantic layout, bounded load/recompute/plot/export/restore workflow | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Gait Analysis | Video Marker producer-reader compatibility, segmentation/timing roles, project migration, CSV result, presentation, bounded navigation/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Batch Crop | core/rotated crop geometry, padded-edge policy, duplicate tasks/outputs, preview viewport preservation, physical size export, manifest and overwrite policy, generic semantic layout | Covered: direct geometry, task, result, and preview specifications replace legacy automated behavior; native ROI pointer feel remains an explicit ManualCheck. | +| Curvature | circle/length science, invalid-curve branches, fit/length task fingerprints, source migration, result schema, source/presentation, bounded trace/fit/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| FLIR Thermal | raw fallback, correction/default warning, extrema, ROI measurement, project/result/source/presentation, shared display range, bounded radiometric display/reading/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Focus Stack | fusion, registration, project/result/source/presentation, empty-source failure, generic semantic layout, bounded load/fuse/export/restore workflow | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Image Enhance | basic enhancement, white balance, white-ROI calibration, subject-preserving enhancement, ROI availability/defaults, preview scaling, per-image export manifest, source/result/presentation, generic semantic layout | Covered: direct capability specs now replace the legacy behavioral and layout tests without a wrapper class. | +| Image Match | white-balance, tone, protected-tone, Lab-style and histogram matching; reference separation; source/result/project/presentation; bounded reference-match/export/restore workflow; generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Video Marker | editable skeleton lifecycle, coarse/subpixel deterministic tracking, prediction cache, legacy project and annotation migration, marker/coordinate provenance, bounded marking/prediction/calibration/export/restore workflow, project/result/source/presentation | Covered: direct capability and hidden-GUI workflow specs replace the legacy wrappers. The optional Vision Toolbox comparator is explicitly retired: production has no Toolbox dependency, and deterministic synthetic tracking behavior is the retained contract. | +| Figure Studio | style, overlay order, source limits/geometry, composite FIG import/export, canvas/title/log-axis edge cases, version migrations, axes-source handoff, bounded FIG preview/export workflow, project/presentation, generic semantic layout | Covered: direct capability and bounded GUI specs replace the legacy high-value behavior without restoring its wrappers. | +| Nerve Response Analysis | train detection, roles, CAP metrics, migration, source/result/presentation, synthetic filter-record/protocol session, bounded analysis/export/reset/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| Response Review Stats | CSV parsing, aligned metrics, migration, result/presentation, bounded load/preview/export/reset/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| RHS Preview | role assignment, timing, migration, result/source/presentation, synthetic recording/filter discovery, bounded preview/ROI/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | +| T-test Wizard | input table, layered labels, Welch/pooled/paired/directional/error statistics, project migration, CSV result schema, generic semantic layout | Covered: direct source, run, persistence, result, and structural specs replace the legacy core/layout wrappers. | +| ECG Print | input controls, signal products, migration, result/presentation, bounded load/analyze/four-plot/export/restore workflow, generic semantic layout | Covered: direct capability and hidden-GUI workflow specs replace the legacy behavioral and layout wrappers. | + +Repository guardrails are now classified as follows. Sensitive-data hygiene is +retained as a platform-independent tracked-text contract (user/drive paths and +sample timestamps). App/package ownership and launcher conformance are retained +through `TestCatalogSpec`, public-App source routing, definition conformance, +and path-isolated evidence. Public help and rendered documentation remain +validated by the dedicated docs build/check tasks. Release/version, dependency, +magic-number, rectangle-geometry, and Code Analyzer implementation scans are +explicitly retired: their old private-text heuristics do not prove a public +contract and conflict with the current ownership/metadata model. Their durable +rules live in `AGENTS.md`, version metadata, public help, and release workflow. #### ManualChecks trial @@ -112,7 +124,7 @@ architecture. #### Execution plan -1. **Framework closure.** Add an isolated profile to Build and CI; make +1. **Framework closure.** Add a path-isolated profile to Build and CI; make isolation aggregate every App failure; make changed fallback include the required environments; add the source-route/exemption guardrail; trial the bounded ManualChecks model above. @@ -166,7 +178,7 @@ file length, helper count, or a possible future abstraction as migration debt. Temporary MathWorks Toolbox use must record the exact source symbol, product, owner, repository fallback, fallback test, idempotency evidence, numeric parity outputs and tolerance, and the condition for deleting the Toolbox branch. Its -machine-readable declaration lives in `tests/runner/labkitToolboxDebt.m`. +machine-readable declaration lives in `tests/+labkittest/toolboxDebt.m`. When an entry is resolved, delete it and any debt-only guardrail in the same change. Preserve durable decisions and evidence in the owning manual and diff --git a/.agents/skills/labkit-test-planner/SKILL.md b/.agents/skills/labkit-test-planner/SKILL.md index 49073cc5a..72eb3204e 100644 --- a/.agents/skills/labkit-test-planner/SKILL.md +++ b/.agents/skills/labkit-test-planner/SKILL.md @@ -48,9 +48,11 @@ startup, licensing, reporting, progress, and failure-diagnosis costs. - `buildtool headless` runs every `Env:headless` identity. - `buildtool gui` runs every `Env:hidden-gui` identity with hidden figures. +- `buildtool isolated` runs every `Env:path-isolated` identity. - `buildtool coverage` adds Cobertura XML and HTML coverage to headless. - `buildtool changedFast` maps local Git paths to exact evidence closures. A - framework, build, policy, or unknown path safely widens to full headless. + framework, build, policy, or unknown path safely widens to every automated + environment. - Hidden GUI proves declared structural wiring, not native dialogs, visual quality, pointer feel, real-data suitability, or scientific validity. diff --git a/.agents/skills/labkit-test-planner/scripts/runLabKitTestTarget.m b/.agents/skills/labkit-test-planner/scripts/runLabKitTestTarget.m deleted file mode 100644 index 5664716c4..000000000 --- a/.agents/skills/labkit-test-planner/scripts/runLabKitTestTarget.m +++ /dev/null @@ -1,134 +0,0 @@ -function output = runLabKitTestTarget(action, options) -%RUNLABKITTESTTARGET Run one focused LabKit test target consistently. -% Expected caller: Codex agents using the labkit-test-planner skill. -% Inputs: -% action "list-file", "run-file", "run-test", or "run-suite" -% options.File test file beneath tests/cases; optional for run-test when -% the canonical class name has one unique owning file -% options.Test canonical ClassName or ClassName/methodName selector -% options.Suite suite folder relative to tests/cases -% options.Gui include hidden GUI tests for a suite; file actions infer it -% Output: -% output runLabKitTests result or list-only result -% Side effects: runs MATLAB tests and writes normal ignored test artifacts. - - arguments - action (1, 1) string {mustBeMember(action, ... - ["list-file", "run-file", "run-test", "run-suite"])} - options.File (1, 1) string = "" - options.Test (1, 1) string = "" - options.Suite (1, 1) string = "" - options.Gui (1, 1) logical = false - end - - skillRoot = fileparts(fileparts(mfilename("fullpath"))); - repoRoot = fileparts(fileparts(fileparts(skillRoot))); - addpath(fullfile(repoRoot, "tests")); - - commonArgs = { ... - "GuiMode", "hidden", ... - "HtmlReport", false, ... - "RunName", "focused"}; - - switch action - case "list-file" - requireValue(options.File, "File", action); - rejectValue(options.Test, "Test", action); - rejectValue(options.Suite, "Suite", action); - output = runLabKitTests( ... - "Files", options.File, ... - "IncludeGui", isGuiTestFile(repoRoot, options.File), ... - "ListOnly", true, ... - commonArgs{:}); - case "run-file" - requireValue(options.File, "File", action); - rejectValue(options.Test, "Test", action); - rejectValue(options.Suite, "Suite", action); - output = runLabKitTests( ... - "Files", options.File, ... - "IncludeGui", isGuiTestFile(repoRoot, options.File), ... - commonArgs{:}); - case "run-test" - requireValue(options.Test, "Test", action); - rejectValue(options.Suite, "Suite", action); - testFile = options.File; - if strlength(testFile) == 0 - testFile = resolveOwningTestFile(repoRoot, options.Test); - end - output = runLabKitTests( ... - "Files", testFile, ... - "Tests", options.Test, ... - "IncludeGui", isGuiTestFile(repoRoot, testFile), ... - commonArgs{:}); - case "run-suite" - requireValue(options.Suite, "Suite", action); - rejectValue(options.File, "File", action); - rejectValue(options.Test, "Test", action); - output = runLabKitTests( ... - "Suites", options.Suite, ... - "IncludeGui", options.Gui || isGuiSuite(options.Suite), ... - commonArgs{:}); - end -end - -function file = resolveOwningTestFile(repoRoot, selector) - parts = split(selector, "/"); - className = parts(1); - if strlength(className) == 0 || ~isvarname(className) - error("LabKit:AgentTestTarget:InvalidSelector", ... - "run-test Test must begin with a canonical MATLAB test class name."); - end - matches = dir(fullfile( ... - repoRoot, "tests", "cases", "**", className + ".m")); - matches = matches(~[matches.isdir]); - if isempty(matches) - error("LabKit:AgentTestTarget:OwnerNotFound", ... - "No test file owns canonical class %s.", className); - end - if numel(matches) > 1 - candidates = string(fullfile( ... - {matches.folder}, {matches.name})); - error("LabKit:AgentTestTarget:AmbiguousOwner", ... - "Canonical class %s has multiple owning files; supply File:%s%s", ... - className, newline, strjoin(candidates, newline)); - end - file = string(fullfile(matches(1).folder, matches(1).name)); -end - -function tf = isGuiTestFile(repoRoot, file) - file = normalizePath(file); - guiRoot = lower(normalizePath( ... - fullfile(repoRoot, "tests", "cases", "gui"))) + "/"; - isAbsolute = startsWith(file, "/") || startsWith(file, "//") || ... - ~isempty(regexp(file, "^[A-Za-z]:/", "once")); - if isAbsolute - fullFile = lower(file); - else - fullFile = lower(normalizePath(fullfile(repoRoot, file))); - end - tf = startsWith(fullFile, guiRoot) || ... - startsWith(lower(file), "gui/"); -end - -function tf = isGuiSuite(suite) - suite = strip(normalizePath(suite), "both", "/"); - tf = startsWith(suite, "gui/"); -end - -function path = normalizePath(path) - path = replace(string(path), "\", "/"); -end - -function requireValue(value, name, action) - if strlength(value) == 0 - error("LabKit:AgentTestTarget:MissingOption", ... - "%s requires the %s option.", action, name); - end -end - -function rejectValue(value, name, action) - if strlength(value) > 0 - error("LabKit:AgentTestTarget:UnexpectedOption", ... - "%s does not accept the %s option.", action, name); - end -end diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71481528f..06499473f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,6 +84,71 @@ jobs: artifacts/debug/** artifacts/logs/** + isolated-platforms: + name: Path isolation / ${{ matrix.label }} + runs-on: ${{ matrix.os }} + timeout-minutes: 35 + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + id: linux + label: Linux + - os: macos-14 + id: macos + label: macOS + - os: windows-latest + id: windows + label: Windows + steps: + - name: Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 2 + + - name: Set up clean MATLAB runtime + uses: matlab-actions/setup-matlab@v3 + with: + release: ${{ env.MATLAB_RELEASE }} + + - name: Prepare MATLAB log directory + shell: bash + run: mkdir -p artifacts/logs/isolated + + - name: Run path-isolation validation + timeout-minutes: 30 + uses: matlab-actions/run-build@v3 + with: + tasks: isolated + startup-options: -logfile artifacts/logs/isolated/matlab.log + + - name: Summarize path-isolation validation + if: always() + shell: bash + run: | + if [ -f artifacts/test-results/isolated/junit.xml ]; then + python .github/scripts/summarize_junit.py \ + artifacts/test-results/isolated/junit.xml \ + --run-name "isolated-${{ matrix.id }}" \ + --log artifacts/logs/isolated/matlab.log \ + --active-test artifacts/test-results/isolated/active-test.json + else + echo "::warning::Path-isolation validation did not produce JUnit output." + fi + + - name: Upload path-isolation artifacts + if: always() + uses: actions/upload-artifact@v7 + with: + name: matlab-isolated-${{ matrix.id }} + if-no-files-found: warn + retention-days: 14 + path: | + artifacts/test-results/** + artifacts/debug/** + artifacts/logs/** + gui-platforms: name: Hidden GUI / ${{ matrix.label }} runs-on: ${{ matrix.os }} diff --git a/buildfile.m b/buildfile.m index be22d2a5d..15bb350b8 100644 --- a/buildfile.m +++ b/buildfile.m @@ -3,6 +3,7 @@ % buildtool changedFast local semantic pre-commit evidence % buildtool headless every headless specification % buildtool gui every hidden-GUI specification +% buildtool isolated every path-isolated specification % buildtool coverage headless specifications with coverage artifacts % buildtool docs render documentation % buildtool docsCheck verify generated documentation @@ -23,6 +24,10 @@ function guiTask(~) runTests("gui"); end +function isolatedTask(~) +runTests("isolated"); +end + function coverageTask(~) runTests("coverage", Coverage=true); end @@ -40,6 +45,7 @@ function listTasksTask(~) fprintf(" changedFast local semantic pre-commit evidence\n"); fprintf(" headless every headless specification\n"); fprintf(" gui every hidden-GUI specification\n"); +fprintf(" isolated every path-isolated specification\n"); fprintf(" coverage headless specifications with coverage artifacts\n"); fprintf(" docs render documentation\n"); fprintf(" docsCheck verify generated documentation\n"); diff --git a/docs/development/maintain-and-release/testing.md b/docs/development/maintain-and-release/testing.md index 5047291b2..4d9a0cbb7 100644 --- a/docs/development/maintain-and-release/testing.md +++ b/docs/development/maintain-and-release/testing.md @@ -76,12 +76,13 @@ Contracts describe evidence, not test cost: | `definition` / `product` | parameterized public App conformance | | `system` | build, repository, CI, documentation, packaging, and release guardrails | -Environments are `headless`, `hidden-gui`, and `isolated-process`. +Environments are `headless`, `hidden-gui`, and `path-isolated`. Headless tests do not prove GUI behavior. Hidden-GUI conformance proves that an App can build its declared layout; it does not prove native dialogs, pointer -feel, visual quality, real lab data, or scientific review. The isolated-process -conformance probes every public App from reset paths in one child MATLAB -process, retaining the path boundary without paying one cold startup per App. +feel, visual quality, real lab data, or scientific review. The path-isolated +conformance probes every public App from a reset path boundary in the already +running catalog executor. It retains the deployable path boundary and batches +all App results without requiring a second concurrent MATLAB license. ## Build Tasks @@ -91,6 +92,7 @@ Use stable Build tasks for branch and CI gates: buildtool changedFast buildtool headless buildtool gui +buildtool isolated buildtool coverage buildtool docs buildtool docsCheck @@ -101,14 +103,16 @@ buildtool docsCheck | `changedFast` | Local final pre-commit/pre-push gate. Reads tracked and untracked working-tree paths; on a clean checkpoint it reads `HEAD^..HEAD`. | | `headless` | Every headless catalog identity. | | `gui` | Every hidden-GUI catalog identity. | +| `isolated` | Every path-isolated catalog identity. | | `coverage` | Headless catalog with Cobertura XML and HTML coverage artifacts. | | `docs` / `docsCheck` | Render or verify the generated documentation site. | `changedFast` prints semantic reasons and exact identities. For ordinary App and facade source it runs only the required contract closure. A framework, -Build, catalog, policy, or unknown path deliberately widens to every headless -specification: broad selection is a visible safety boundary, not a planner -failure. Do not weaken that fallback to make a route count look smaller. +Build, catalog, policy, or unknown path deliberately widens to every automated +environment: headless, hidden-GUI, and path-isolated. Broad selection is a +visible safety boundary, not a planner failure. Do not weaken that fallback to +make a route count look smaller. Run focused behavior during iteration. Run `changedFast` once when the branch is ready for review or direct-main integration. CI owns broad platform @@ -134,9 +138,16 @@ the smallest owner/contract or exact source that proves the repair. A zero selection or missing-contract error is a test-authoring defect, never passing evidence. +When a mapped layout change leaves a non-automatable boundary, its plan can +name a manual check. It is printed and recorded in `plan.json`, but it never +makes an automated run pass. Manual checks are limited to native dialogs, +pointer behavior, visual design, real-data suitability, and scientific +interpretation; they cannot replace an automated calculation, state, export, +migration, structural-GUI, or workflow proof. + ## CI and Manual Evidence -Continuous Integration runs `headless` and `gui` on Linux, macOS, and Windows +Continuous Integration runs `headless`, `gui`, and `isolated` on Linux, macOS, and Windows from a clean MATLAB runtime without optional Toolboxes. It uploads the catalog artifacts even after failure. Coverage is an explicit report, not a duplicate CI gate. diff --git a/site/assets/search-index.js b/site/assets/search-index.js index a69efe615..c6ccee857 100644 --- a/site/assets/search-index.js +++ b/site/assets/search-index.js @@ -1 +1 @@ -window.LABKIT_SEARCH_INDEX = [{"title":"LabKit Documentation","url":"index.html","kind":"overview","section":"general","keywords":"LabKit Documentation","text":"LabKit Documentation LabKit documentation is organized by the question you are trying to answer. Start with a task guide, then open an API reference only when you need exact MATLAB call syntax or returned data shapes. Choose A Starting Point I want to Start here Install, update, or open LabKit [Getting started](getting-started/README.md) Understand every launcher action or call it from MATLAB [LabKit Launcher](apps/labkit-core/launcher/README.md) Choose an app and understand its inputs and outputs [App guide](apps/README.md) Call a reusable `labkit.*` function [Public API reference](reference/README.md) Understand ownership and package boundaries [Architecture](development/build-apps/architecture.md) Create or modify an app [App development](development/build-apps/app-development.md) Run tests or diagnose performance [Testing](development/maintain-and-release/testing.md) Call packaging, profiling, codecheck, or documentation tools [Maintainer tools](development/tools/README.md) Understand documentation sources and generated HTML [Documentation system](development/maintain-and-release/documentation.md) Maintain a private app workspace [Private apps](development/maintain-and-release/private-apps.md) Prepare a release [Release process](development/maintain-and-release/release.md) Documentation Layers getting-started/ installation, launcher, updates, and first-run concepts apps/ one directory per family and one subdirectory per app including the LabKit Launcher under LabKit Core framework/ UI runtime concepts, behavior, and app-authoring contracts libraries/ one directory per reusable public MATLAB facade reference/ generated-function reference landing page development/ reader-task folders for app building, maintenance, and tools history/ chronological change records and the project history index Every Markdown file is published automatically. Its path owns navigation and its first level-one heading owns the page title. Public App manuals are matched to `labkit_launcher(\"list\")`; App-owned function pages are discovered from complete public MATLAB help contracts. Reference Conventions Public function pages follow the MATLAB reference pattern: summary and syntax description and behavior input arguments and options output arguments and data shapes algorithms or scientific semantics where relevant errors and limitations executable examples version history, See Also, and related topics Each app family has a landing page. Each concrete app owns a directory whose `README.md` is its Get Started and detailed behavior page; complex apps can add focused workflow, file-format, or algorithm topics beside it. App pages explain launch, task flow, interaction rules, inputs, outputs, persistence, scientific meaning, non-GUI APIs, errors, limitations, examples, related topics, and component history as applicable. They do not document internal callbacks. Framework and library landing pages follow the Qt module pattern: overview and ownership first, followed by grouped concepts, supported public members, detailed behavior, examples, and related modules. Generated function pages are owned by MATLAB source help blocks. Handwritten HTML is never a source. Project History And Support [Project history](history/README.md) lists all change records and connects them to the affected apps, framework, and libraries. [Support](../.github/SUPPORT.md) explains how to report workflow problems."},{"title":"EIS","url":"apps/electrochemistry/eis.html","kind":"app","section":"apps","keywords":"apps electrochemistry eis EIS","text":"EIS EIS overlays impedance data from one or more Gamry `ZCURVE` tables, supports Nyquist and Bode-style axis combinations, and exports the values currently selected for plotting. Requirements And Launch labkit_EIS_app Inputs Add one or more `.DTA` files containing a readable EIS `ZCURVE`. Files that do not contain the required curve are reported and omitted from the plot. The successfully decoded source list and its order are preserved in project state through portable references. Basic Workflow Add the EIS DTA files. Choose X and Y quantities. Enable logarithmic X or Y scaling only for strictly positive plotted data. Use **Fit X/Y limits** to re-estimate independent limits from the current data, or **Use equal X/Y scale** when equal data units are wanted. Adjust marker, line, grid, and legend presentation. Export the current plot data CSV. Axis Quantities The available quantities are frequency, log10 frequency, time, point number, real impedance, imaginary impedance, negative imaginary impedance, impedance magnitude, phase, DC current, and DC voltage. Default axes are `Zreal (ohm)` and `-Zimag (ohm)`. Use `Zreal` versus `-Zimag` for the conventional Nyquist orientation. Use frequency versus magnitude or phase for Bode-style views. The log-axis checkbox changes MATLAB axes scaling; choosing `log10(Freq)` changes the data coordinate itself. Do not apply both transformations unless that is explicitly intended. Plot Parameters Parameter Default Line width 1.4 Marker size 6 Show markers on Log X / Log Y off / off Legend / Grid on / on The app never infers an equal aspect ratio from the selected quantities: a Nyquist plot starts with independently fitted limits. Use **Use equal X/Y scale** only when equal data units are useful for the current comparison. Use **Fit X/Y limits** to return to independent limits after equal scaling or a manual zoom. Equal scaling expands a fitted limit when necessary so X and Y data units have the same on-screen length; it is a one-time reset and does not constrain later wheel zooming. Axis and styling changes preserve the current source set and the current viewport; the two view buttons explicitly replace that viewport. Output **Export current plot CSV** writes the selected X/Y values for each valid file on a shared row index. Each file retains its own X and Y pair, so unequal curve lengths do not imply interpolation. A result manifest records the selected axes, plot parameters, source references, and output role. Use Without The GUI [item, status] = labkit.dta.loadFile(\"spectrum.DTA\", \"eis\"); assert(status.ok, status.message); curve = labkit.dta.getZCurve(item); x = eis.analysisRun.valuesForAxis(curve, \"Zreal (ohm)\"); y = eis.analysisRun.valuesForAxis(curve, \"-Zimag (ohm)\"); plot(x, y, \"o-\"); axis equal `valuesForAxis` is app-owned and not currently part of the published app API catalog. The DTA loader and `getZCurve` are supported reusable APIs. Errors And Limitations Log axes omit or reject nonpositive coordinates according to MATLAB axes behavior; inspect the data rather than treating missing points as zero. Overlaying files does not normalize electrode area or fixture geometry. Axis labels describe parsed DTA columns; they do not validate the experiment configuration recorded by the instrument. Related Topics [Electrochemistry family](../README.md) [DTA Library](../../../libraries/dta/README.md) [API Reference](../../../reference/README.md)"},{"title":"2.1: RHS apps and shared runtime stability","url":"history/records/2026/06/LK-20260621-v2-1-rhs-and-runtime-stability.html","kind":"history","section":"history","keywords":"LK-20260621-v2-1-rhs-and-runtime-stability 2026-06-21 7 feat compatible historical project evolution","text":"2.1: RHS apps and shared runtime stability id: LK-20260621-v2-1-rhs-and-runtime-stability date: 2026-06-21 sequence: 7 type: feat compatibility: compatible scope: historical project evolution Context After v2.0, the UI runtime supported several app families but still repeated important behavior around busy actions, path events, preview zoom, and layout ownership. A new neurophysiology family would amplify those inconsistencies if each app solved them independently. Decision and rationale Add RHS reading and review as a first-class app family while centralizing only the runtime mechanics shared across domains. Filtering choices and response analysis remained in the RHS workflows; transactions, path events, zoom, and layout ownership belonged to the UI layer. Changes Added RHS Preview, Nerve Response Analysis, and Response Review Stats. Folded the separate screening step into preview filtering so file review used one workflow rather than two overlapping stages. Added duplicate Batch Crop tasks for repeated crop layouts. Unified preview scroll zoom and centralized action busy transactions. Centralized path-event contracts and app layout ownership. Added a ZIP-based updater and stabilized image and app interactions before release. Reduced focused test discovery and guardrail cost as the repository grew. User and data impact Neurophysiology users gained file preview, response analysis, and review statistics apps. Existing users saw more consistent zoom, busy feedback, path updates, and responsive layout behavior. The updater provided a repository- owned way to install a packaged release. Compatibility and migration The RHS family was additive. UI implementations that maintained their own copies of busy, path, or layout mechanics were migrated to the shared runtime contracts. Validation The stage added RHS-focused tests, interaction regressions, compatibility input checks, path-event checks, and faster focused test routing. Tag `2.1` points to `76ddf7d0`. Evidence RHS app family `7ddc036f` and preview filtering `ca8a37dd`. Shared interaction mechanics `eb52eb17`, `f3e42b8e`, `1fe89ba2`. Layout ownership `3ce4c8f7`, `09baf7fe`. Updater `e4b02f3a`. 2.1 release stabilization `76ddf7d0`. Known limitations and follow-up The updater still depended on how the launcher was installed, and several image workflows reset zoom or recomputed previews during edits. The following 2.2 and 2.3 releases concentrated on self-contained launch and direct image manipulation."},{"title":"Adjacent navigation for history records","url":"history/records/2026/07/LK-20260716-history-adjacent-navigation.html","kind":"history","section":"history","keywords":"LK-20260716-history-adjacent-navigation 2026-07-16 64 docs compatible documentation `tools/docs/` `site/history/records/`","text":"Adjacent navigation for history records id: LK-20260716-history-adjacent-navigation date: 2026-07-16 sequence: 64 type: docs compatibility: compatible component: `documentation` scope: `tools/docs/` scope: `site/history/records/` Context The complete timeline linked every recorded change, but a reader who opened one detail page had to return to the index before continuing chronologically. Dates and filenames could not safely identify adjacent records because several changes may share one date. Decision and rationale Use validated history `sequence` metadata to add adjacent-record links at the end of every rendered history detail page. **Previous change** means the record with `sequence - 1`; **Next change** means `sequence + 1`. This preserves one unambiguous project-history order without binding authored content to Git. Changes Added responsive previous/next navigation immediately before the generated page footer. Showed only existing directions at the oldest and newest ends. Added regression coverage for link targets, ordering, and page placement. User and data impact Readers can traverse project history linearly without returning to the index. No MATLAB runtime, app state, scientific data, or exports change. Compatibility and migration Existing history URLs and record metadata remain valid. Regenerating `site/` adds navigation to every record page and updates the search index normally. Validation Renderer regression tests verify middle and endpoint records against source sequence metadata. The documentation consistency check independently rebuilds and byte-compares the tracked site. Evidence `renderLabKitHistorySequenceNavigation` owns adjacent link generation. `DocumentationRendererRegressionTest` verifies the generated navigation. Known limitations and follow-up Navigation is intentionally chronological across all project components. It does not filter to the current app or library; component-specific history remains available from each component manual."},{"title":"App SDK explicit contract replaces the retired UI runtime","url":"history/records/2026/07/LK-20260719-ui-explicit-contract-migration.html","kind":"history","section":"history","keywords":"LK-20260719-ui-explicit-contract-migration 2026-07-19 138 refactor breaking labkit.app labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_GaitAnalysis_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_VideoMarker_app labkit_FigureStudio_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_TTestWizard_app labkit_ECGPrint_app App Framework DIC Electrochem Gait Image Measurement LabKit Core Neurophysiology Statistics Wearable Project persistence Result provenance","text":"App SDK explicit contract replaces the retired UI runtime id: LK-20260719-ui-explicit-contract-migration date: 2026-07-19 sequence: 138 type: refactor compatibility: breaking component: `labkit.app` | `new -> 1.0.0` component: `labkit_DICPostprocess_app` | `1.4.7 -> 1.5.0` component: `labkit_DICPreprocess_app` | `1.5.8 -> 1.6.0` component: `labkit_ChronoOverlay_app` | `1.4.7 -> 1.5.0` component: `labkit_CIC_app` | `1.4.7 -> 1.5.0` component: `labkit_CSC_app` | `1.4.8 -> 1.5.0` component: `labkit_EIS_app` | `1.4.7 -> 1.5.0` component: `labkit_VTResistance_app` | `1.4.7 -> 1.5.0` component: `labkit_GaitAnalysis_app` | `2.0.8 -> 2.1.0` component: `labkit_BatchImageCrop_app` | `1.7.7 -> 1.8.0` component: `labkit_CurvatureMeasurement_app` | `1.4.6 -> 1.5.0` component: `labkit_FLIRThermal_app` | `1.4.8 -> 1.5.0` component: `labkit_FocusStack_app` | `1.5.6 -> 1.6.0` component: `labkit_ImageEnhance_app` | `1.6.7 -> 1.7.0` component: `labkit_ImageMatch_app` | `1.6.8 -> 1.7.0` component: `labkit_VideoMarker_app` | `1.5.7 -> 1.6.0` component: `labkit_FigureStudio_app` | `0.2.9 -> 0.3.0` component: `labkit_NerveResponseAnalysis_app` | `1.4.8 -> 1.5.0` component: `labkit_ResponseReviewStats_app` | `1.4.7 -> 1.5.0` component: `labkit_RHSPreview_app` | `1.4.6 -> 1.5.0` component: `labkit_TTestWizard_app` | `1.0.1 -> 1.1.0` component: `labkit_ECGPrint_app` | `1.4.6 -> 1.5.0` scope: App Framework scope: DIC scope: Electrochem scope: Gait scope: Image Measurement scope: LabKit Core scope: Neurophysiology scope: Statistics scope: Wearable scope: Project persistence scope: Result provenance Context The retired UI runtime removed substantial per-App lifecycle code, but Apps still registered callback tables, repeated bound values in presenters, authored standard file add/remove/clear behavior, and depended on nested event/service structs. A replacement SDK kernel had already established immutable semantic values, pre-GUI validation, transactional state/presentation commits, project documents, result manifests, resources, and portable sources. The migration then had to restore the complete behavior and visual contract of every tracked App before the retired production facade could be deleted. Decision and rationale Create `labkit.app` as the stable SDK rather than misnaming the expanded contract `labkit.ui` or adapting it back to Runtime V2 transport structs. Keep the public root small, partition authoring by capability, and concentrate complexity in a paved path: direct-callback `layout.*` nodes, strict bindings, runtime-completed `view.Snapshot` values, standard file lifecycle, fixed `CreateSession(project,context)`, and private native adapters. Migrate all 21 tracked Apps through capability waves, treating their previous controls, tabs, layout proportions, interactions, project behavior, results, debug samples, and workflow wording as product contracts rather than reducing the task to launch compatibility. Changes Added the private native MATLAB adapter with semantic component ownership, typed RuntimeKernel callbacks, native dialog results, complete-presentation reconciliation, and rollback to the previous native view after a failed renderer commit. Added `Definition.launch`, fixed renderer `(axes,model)` dispatch, semantic labels, runtime-owned file add/remove/clear and selection, and transient session rebuild after source collection changes. Added strict table view options, typed complete-data edits, and distinct `event.TableCellEdit`, `event.TableCellSelection`, and `event.ListSelection` values; the private adapter absorbs native MATLAB table-value differences. Fixed session construction to `CreateSession(project,context)` so Apps resolve opaque portable sources without reading their representation. Migrated Chrono Overlay to one directly bound export callback, four state bindings, one directly bound two-axis renderer, and a two-operation view snapshot. Partitioned the public SDK into `layout`, `view`, `event`, `project`, `result`, and `dialog`; layout nodes, option parsing, stores, adapters, and runtime execution remain hidden under `internal`. Reduced Chrono's noncomment layout/action/presenter code from 277 lines to 86 while preserving its DTA alignment, plot options, project schema, CSV columns, and result provenance. Migrated T-Test Wizard as the typed editable-table, feature-fragment, and multi-page workspace proof: table selections and edits have explicit payload classes, `+workbench` exposes product assembly, workflow packages own their layout/presentation/actions, and the private adapter owns concrete layout. Migrated VT Resistance to direct file and analysis-setting bindings, a complete summary/table/two-axis snapshot, and an App-owned result-package export. Plot renderers and scientific choices now live with their owning analysis capabilities instead of a technical UI package. Migrated Gait Analysis to capability-owned source adoption, option invalidation, deterministic analysis, step selection/navigation, three-axis rendering, CSV-set export, and result packaging. Migrated DIC Preprocess to two role-bound image sources, paired-anchor registration, managed crop and mask editors, two-axis rendering, edit replay, and result-package exports owned by its analysis, mask, and result capabilities. Migrated Batch Image Crop to framework-owned source selection plus App-owned duplicate crop tasks, direct crop-center and scale-reference interactions, capability snapshots, and result-package export. Added `labkit.app.project.sourceRecord` so pure payload migrations can convert legacy paths into portable sources without constructing the framework-owned reference representation. Corrected folder chooser dispatch to its one-path backend contract and applied table data before table selection during native reconciliation, so a selection may legally target rows introduced by the same snapshot. Preserved cell-valued interaction payloads in the transactional event queue and kept multi-target interaction bridge specifications scalar, enabling paired-anchor gestures across two semantic axes. Removed handler objects, callback tables, renderer registries, and their forwarding from the App authoring contract. Layout controls and plot areas reference concrete functions directly. Migrated the remaining electrochemistry, DIC, image-measurement, neurophysiology, core, wearable, and high-state workflows, including editable tables, workspace pages, file roles, multi-axis plots, managed point/rectangle/interval/scale interactions, long-lived video resources, project recovery, result packages, and synthetic diagnostic samples. Restored shared product presentation: versioned titles and dirty markers, startup progress and failure surfaces, guarded close behavior, utility menus, adjustable pane dividers, scroll and grow policies, numeric panners, adaptive action grids, usage text, plot navigation, pop-out/export tools, and viewport-preserving overlays. Internalized contract compilation, runtime construction, native platform plans, target inventories, and callback-context creation. `Definition` is the sole author-created root; `CallbackContext` is a sealed runtime-injected port; optional concepts remain grouped under purpose-specific packages. Deleted the complete retired `labkit.ui` production facade and the migration-only analyzer, prototypes, compatibility tools, and debt-only tests after source scans and focused App tests proved that no production consumer remained. User and data impact Chrono Overlay retains its input formats, pulse-gap alignment, plot meanings, parameter defaults, CSV table, and version-2 project payload. T-Test Wizard retains its source formats, group/test calculations, plot meaning, two CSV exports, and version-2 project payload. VT Resistance retains its pulse detection, resistance calculations, plot semantics, CSV schema, and version-1 project payload while recomputing the decoded batch under shared settings. Gait Analysis retains its Video Marker payload contract, project migrations, step segmentation, gait metrics, CSV set, and version-3 project payload. File identities and portable paths remain runtime-owned. DIC Preprocess retains its rigid registration, common crop, mask editing, image/mask exports, and version-1 project payload. Batch Image Crop retains duplicate tasks per source, fixed-pixel and physical crops, rotation/padding, scale calibration, scale-bar placement, image/CSV exports, and its version-2 payload. Existing payload migrations remain App-owned. The other 15 Apps retain their documented source formats, scientific calculations, units, thresholds, project payload versions, export schemas, and result meanings. Their product versions advance once from the `main` baseline to identify the new App SDK source contract and restored complete UI behavior. No project payload version was increased merely because the UI framework changed. Compatibility and migration `labkit.app` 1 is a source-breaking replacement contract for App definitions, presenters, callbacks, events, and interactions. Every tracked App migrated before the retired `labkit.ui` boundary was deleted; there is no runtime adapter or dual authoring surface. Public App entrypoint commands remain stable. Project documents retain their format and App payload versions independently of the facade transition. Validation Focused headless tests cover strict values, transactional runtime behavior, project save/restore, authoring defaults, and Chrono calculations/exports. Hidden GUI tests cover native semantic construction, typed control and table callbacks, bound side effects, standard file lifecycle, transient session rebuild, two-axis rendering, viewport preservation, renderer rollback, Chrono export, and project restore. VT Resistance focused tests cover resistance calculations, CSV compatibility, native layout, shared batch recomputation, two-axis rendering, result packaging, and project restore. Gait focused tests cover project migration, pose decoding, scientific calculations, CSV compatibility, typed table navigation, three-axis rendering, folder selection, result packaging, and project restore. DIC Preprocess focused tests cover project state, image loading, edit replay, registration/crop/mask helpers, export manifests, native two-axis layout, paired-anchor alignment, and managed crop interaction. Framework regression tests cover cell-valued event payloads and native multi-axis interaction bridging. Batch Image Crop focused tests cover crop geometry, padding, physical scaling, project migration, duplicate tasks, output planning/writes, native semantic layout, current-center editing, and standard result manifests. Focused framework and App tests additionally cover all 21 semantic layouts, typed events, managed interactions, project migration/recovery, result writing, synthetic sample packs, diagnostics, resource cleanup, window titles, startup success/failure, close behavior, and native adapter reconciliation. Evidence [Chrono Overlay](../../../../apps/electrochemistry/chrono-overlay/README.md) [VT Resistance](../../../../apps/electrochemistry/vt-resistance/README.md) [Gait Analysis](../../../../apps/gait/gait-analysis/README.md) [DIC Preprocess](../../../../apps/dic/dic-preprocess/README.md) [Batch Image Crop](../../../../apps/image-measurement/batch-crop/README.md) [App catalog](../../../../apps/README.md) [LabKit App Framework](../../../../framework/README.md) [Build a Complete App](../../../../development/build-apps/complete-app.md) Known limitations and follow-up Automated GUI evidence does not replace developer-led validation of native dialogs, editable-table feel, pointer interaction, long-lived resource use, representative exports, visual quality, or scientific workflow suitability. That interactive validation remains a release input for the exact integrated commit. labkit.app.project.sourceRecord Create a portable source value during project migration."},{"title":"App SDK supports equal-data-unit plot fitting","url":"history/records/2026/07/LK-20260721-app-sdk-equal-data-unit-fit.html","kind":"history","section":"history","keywords":"LK-20260721-app-sdk-equal-data-unit-fit 2026-07-21 148 fix compatible labkit.app App Framework EIS Overlay","text":"App SDK supports equal-data-unit plot fitting id: LK-20260721-app-sdk-equal-data-unit-fit date: 2026-07-21 sequence: 148 type: fix compatibility: compatible component: `labkit.app` | `1.2.1 -> 1.2.2` scope: App Framework scope: EIS Overlay Context Apps needed an equal X/Y data-unit view for plots such as Nyquist diagrams, but setting an axes aspect mode directly also changed the allocated drawing area and persisted into later wheel and zoom interactions. Decision and rationale Keep viewport geometry in the framework fitter. An App can request equal data units while fitting the current plotted data, after which ordinary framework viewport preservation continues without an aspect lock. Changes Added the public `EqualDataUnits` option to `labkit.app.plot.fitAxesToGraphics`. Fit equal data units by expanding the smaller data span for the current axes pixel geometry, including logarithmic dimensions in log space. Removed the retired EIS axis-label rule; EIS now exposes explicit fit and equal-scale view actions. User and data impact The new option is additive. Existing fit calls keep independent X/Y limits. EIS projects and exports are unchanged; equal scaling is a transient view action and does not alter later zoom or wheel behavior. Compatibility and migration No project or result migration is required. Existing callers retain their independent fit behavior unless they opt into `EqualDataUnits=true`. Validation EIS GUI coverage exercises independent fitting, explicit equal scaling, and later viewport preservation. The App SDK plot helper tests cover finite data, logarithmic axes, and the public option contract. Evidence The fitting helper applies limits from finite plotted data and expands only the smaller working-space span for the axes pixel geometry. The EIS workflow test then verifies that a later framework redraw preserves the chosen viewport. Known limitations and follow-up Developer-led visual validation remains responsible for assessing layout balance on target displays and MATLAB releases. labkit.app.plot.fitAxesToGraphics Fit axes limits to finite plotted X/Y data."},{"title":"App actions require explanatory hover help","url":"history/records/2026/07/LK-20260720-app-action-tooltips.html","kind":"history","section":"history","keywords":"LK-20260720-app-action-tooltips 2026-07-20 140 feat compatible labkit.app labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_GaitAnalysis_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_VideoMarker_app labkit_FigureStudio_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_TTestWizard_app labkit_ECGPrint_app App Framework All tracked Apps","text":"App actions require explanatory hover help id: LK-20260720-app-action-tooltips date: 2026-07-20 sequence: 140 type: feat compatibility: compatible component: `labkit.app` | `1.0.0 -> 1.1.0` component: `labkit_DICPostprocess_app` | `1.5.0 -> 1.5.1` component: `labkit_DICPreprocess_app` | `1.6.0 -> 1.6.1` component: `labkit_ChronoOverlay_app` | `1.5.0 -> 1.5.1` component: `labkit_CIC_app` | `1.5.0 -> 1.5.1` component: `labkit_CSC_app` | `1.5.0 -> 1.5.1` component: `labkit_EIS_app` | `1.5.0 -> 1.5.1` component: `labkit_VTResistance_app` | `1.5.0 -> 1.5.1` component: `labkit_GaitAnalysis_app` | `2.1.0 -> 2.1.1` component: `labkit_BatchImageCrop_app` | `1.8.0 -> 1.8.1` component: `labkit_CurvatureMeasurement_app` | `1.5.0 -> 1.5.1` component: `labkit_FLIRThermal_app` | `1.5.0 -> 1.5.1` component: `labkit_FocusStack_app` | `1.6.0 -> 1.6.1` component: `labkit_ImageEnhance_app` | `1.7.0 -> 1.7.1` component: `labkit_ImageMatch_app` | `1.7.0 -> 1.7.1` component: `labkit_VideoMarker_app` | `1.6.0 -> 1.6.1` component: `labkit_FigureStudio_app` | `0.3.0 -> 0.3.1` component: `labkit_NerveResponseAnalysis_app` | `1.5.0 -> 1.5.1` component: `labkit_ResponseReviewStats_app` | `1.5.0 -> 1.5.1` component: `labkit_RHSPreview_app` | `1.5.0 -> 1.5.1` component: `labkit_TTestWizard_app` | `1.1.0 -> 1.1.1` component: `labkit_ECGPrint_app` | `1.5.0 -> 1.5.1` scope: App Framework scope: All tracked Apps Context The native text-fit adapter copied button text through a column-shaped char conversion. MATLAB therefore received one newline between every character and rendered hover help as a narrow vertical strip. The generated tooltip also only repeated the visible label, so it did not explain the scientific or workflow consequence of an action. Decision and rationale Make explanatory hover help part of the semantic layout contract. Every `layout.button` produces a nonempty Tooltip, and tracked Apps must replace the label-based framework fallback with App-owned explanatory text. File-list actions expose dedicated tooltip fields and retain framework-owned defaults for generic folder, remove, and clear mechanics. Scientific meaning stays in the owning App rather than in the native adapter. All tracked Apps now describe what their actions consume, calculate, mutate, or export. The contract guardrail rejects App tooltips that only repeat the visible action label and also requires an explanatory input-selection tooltip. Changes Preserved char row vectors as one text line during native text fitting, eliminating the injected character-by-character newlines. Added `Tooltip` support with a nonempty label fallback to `layout.button` and dedicated file-list tooltips for choose, folder, recursive folder, remove, and clear actions. Added scientific and workflow-specific text for all 138 tracked App business buttons and all 26 App input selectors. Centralized the shared tooltip contract in the App Framework and App catalog instead of repeating it in every App manual. User and data impact Existing tracked Apps and third-party layouts retain their actions and calculations. Hovering now always shows readable text; tracked Apps additionally carry domain-specific explanations. Compatibility and migration No additional migration applies beyond the compatibility information in the preceding impact section. Validation App SDK unit coverage for required and compiled tooltip values. Cross-App definition guardrail for non-label business and input tooltips. Native adapter GUI coverage for exact tooltip text without injected newlines. DIC Postprocess GUI coverage for scientific action and Ncorr input help. Evidence The validation details above are the supporting evidence for this record. Known limitations and follow-up Developer-led interactive checks should confirm tooltip timing, width, and line wrapping on supported MATLAB releases and desktop platforms."},{"title":"App alerts through UI facade","url":"history/records/2026/06/LK-20260630-app-alerts-through-ui-facade.html","kind":"history","section":"history","keywords":"LK-20260630-app-alerts-through-ui-facade 2026-06-30 22 feat compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_ECGPrint_app App alerts through UI facade","text":"App alerts through UI facade id: LK-20260630-app-alerts-through-ui-facade date: 2026-06-30 sequence: 22 type: feat compatibility: compatible component: `labkit.ui` | `3.2.7 -> 3.2.8` component: `labkit_DICPostprocess_app` | `1.2.2 -> 1.2.3` component: `labkit_DICPreprocess_app` | `1.2.1 -> 1.2.2` component: `labkit_ChronoOverlay_app` | `1.2.0 -> 1.2.1` component: `labkit_CIC_app` | `1.2.0 -> 1.2.1` component: `labkit_CSC_app` | `1.2.0 -> 1.2.1` component: `labkit_EIS_app` | `1.2.0 -> 1.2.1` component: `labkit_VTResistance_app` | `1.2.0 -> 1.2.1` component: `labkit_BatchImageCrop_app` | `1.3.6 -> 1.3.7` component: `labkit_CurvatureMeasurement_app` | `1.2.2 -> 1.2.3` component: `labkit_FocusStack_app` | `1.2.4 -> 1.2.5` component: `labkit_ImageEnhance_app` | `1.3.3 -> 1.3.4` component: `labkit_ImageMatch_app` | `1.3.4 -> 1.3.5` component: `labkit_ECGPrint_app` | `1.2.1 -> 1.2.2` scope: App alerts through UI facade Context Apps opened alerts directly, which made hidden GUI tests unreliable and led to small differences in modal behavior across workflows. Decision and rationale Route user-visible alerts through one UI service that can display a modal message normally and record it safely during hidden tests. Keep each app responsible for the message and the decision that triggers it. Changes `labkit.ui` `3.2.7 -> 3.2.8` DIC, electrochem, image-measurement, and ECG apps patch bumped where alert routing changed. Routed app alerts through hidden-test-safe `labkit.ui.app.showAlert`. User and data impact Errors continued to appear as app alerts, but test and debug runs could capture them without blocking on an invisible dialog. No saved or exported data changed. Compatibility and migration App error conditions and messages remained app-owned. Only the display route changed, so user data and app project formats required no conversion. Validation Commit `8d7c83b1` migrated alert call sites and updated hidden workflow tests across the listed apps. Evidence Main commit `8d7c83b1`. Known limitations and follow-up The historical `labkit.ui.app.showAlert` entry point was later replaced by the injected `services.dialogs.alert` service in Runtime V2."},{"title":"App diagnostics and hardened UI workflows","url":"history/records/2026/06/LK-20260628-app-diagnostics-and-hardened-ui-workflows.html","kind":"history","section":"history","keywords":"LK-20260628-app-diagnostics-and-hardened-ui-workflows 2026-06-28 15 feat compatible labkit_launcher labkit.ui labkit.ui labkit_BatchImageCrop_app labkit_BatchImageCrop_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app App diagnostics and hardened UI workflows","text":"App diagnostics and hardened UI workflows id: LK-20260628-app-diagnostics-and-hardened-ui-workflows date: 2026-06-28 sequence: 15 type: feat compatibility: compatible component: `labkit_launcher` | `1.1.1 -> 1.1.2` component: `labkit.ui` | `3.1.0 -> 3.1.2` component: `labkit.ui` | `3.1.2 -> 3.1.3` component: `labkit_BatchImageCrop_app` | `1.3.0 -> 1.3.1` component: `labkit_BatchImageCrop_app` | `1.3.1 -> 1.3.2` component: `labkit_FocusStack_app` | `1.2.0 -> 1.2.1` component: `labkit_ImageEnhance_app` | `1.2.0 -> 1.2.1` component: `labkit_ImageEnhance_app` | `1.2.1 -> 1.2.2` component: `labkit_ImageMatch_app` | `1.2.0 -> 1.2.1` component: `labkit_NerveResponseAnalysis_app` | `1.2.0 -> 1.2.1` component: `labkit_ResponseReviewStats_app` | `1.2.0 -> 1.2.1` component: `labkit_RHSPreview_app` | `1.2.0 -> 1.2.1` scope: App diagnostics and hardened UI workflows Context When an app stalled or caught an exception, screenshots and the visible Log tab often omitted the active callback and stack information needed to reproduce the problem. Decision and rationale Capture active operations, uncaught crashes, caught errors, and suspected stalls in structured local reports while hardening the UI paths that generate those events. Keep reports outside project data so diagnostics cannot alter results. Changes `labkit.ui` `3.1.0 -> 3.1.3` Batch Crop, Focus Stack, Image Enhance/Match, neurophysiology apps, and the launcher patch bumped where runtime behavior changed. Hardened LabKit UI workflows. Added crash reports, active-operation reports, caught-error reports, and stall diagnostics. User and data impact Debug runs produced evidence that could identify the failing operation and app state without copying laboratory inputs into the repository. Normal projects and exports kept their previous formats. Compatibility and migration The diagnostic files were additive and existing app inputs and saved results remained readable. Debug runs began producing more detailed local artifacts. Validation Commits `e966457b` and `f5bc6f98` updated launcher, framework, and affected app workflow tests for diagnostic creation and hardened callbacks. Evidence Main commits `e966457b` and `f5bc6f98`. Known limitations and follow-up Diagnostics report the state and stack available at capture time; they do not replace a reproducible input or a focused regression test."},{"title":"App file-selection and electrochem control fixes","url":"history/records/2026/07/LK-20260703-app-file-selection-and-electrochem-control-fixes.html","kind":"history","section":"history","keywords":"LK-20260703-app-file-selection-and-electrochem-control-fixes 2026-07-03 33 fix compatible labkit_CIC_app labkit_CIC_app labkit_CSC_app labkit_CSC_app labkit_VTResistance_app labkit_VTResistance_app labkit_BatchImageCrop_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app historical project evolution","text":"App file-selection and electrochem control fixes id: LK-20260703-app-file-selection-and-electrochem-control-fixes date: 2026-07-03 sequence: 33 type: fix compatibility: compatible component: `labkit_CIC_app` | `1.3.1 -> 1.3.2` component: `labkit_CIC_app` | `1.3.2 -> 1.3.3` component: `labkit_CSC_app` | `1.3.1 -> 1.3.2` component: `labkit_CSC_app` | `1.3.2 -> 1.3.3` component: `labkit_VTResistance_app` | `1.3.1 -> 1.3.2` component: `labkit_VTResistance_app` | `1.3.2 -> 1.3.3` component: `labkit_BatchImageCrop_app` | `1.6.2 -> 1.6.3` component: `labkit_FLIRThermal_app` | `1.2.1 -> 1.2.2` component: `labkit_FocusStack_app` | `1.4.1 -> 1.4.2` component: `labkit_ImageEnhance_app` | `1.5.1 -> 1.5.2` component: `labkit_ImageMatch_app` | `1.5.1 -> 1.5.2` scope: historical project evolution Context Adding files to an existing multi-file session could replace or select the wrong entry in several apps. CIC, CSC, and VT Resistance also exposed manual plot controls that no longer matched their intended result-review workflow. Decision and rationale Preserve the complete file list when new selections are appended and select a newly added item predictably. Remove obsolete electrochem controls instead of keeping buttons whose effect was ambiguous or redundant. Changes CIC, CSC, VT Resistance, Batch Crop, FLIR Thermal, Focus Stack, Image Enhance, and Image Match patch bumped for appended file selections. CIC, CSC, and VT Resistance patch bumped again for manual plot-control removal. Preserved appended file selections. Removed electrochem manual plot controls that no longer matched the workflow. User and data impact Users could add another batch without losing files already loaded, across the listed electrochem and image apps. The electrochem workbenches became simpler; calculations and exported result schemas were unchanged. Compatibility and migration Existing loaded-file and result formats remained valid. Appended selections now preserved the active item, and the removed manual plot controls did not alter the underlying calculation options. Validation The file-selection commit added GUI regression coverage to every affected app. The control-removal commit updated the three electrochem GUI workflows and shared test helpers. Exact historical commands were not recorded. Evidence Main commits `6348185e` and `674d5d4b`. Known limitations and follow-up The change covered app-level append handling. Later framework work unified the native file-selection behavior across platforms."},{"title":"App manuals become reader-oriented and focused tests gain one wrapper","url":"history/records/2026/07/LK-20260720-reader-oriented-app-manuals-and-test-wrapper.html","kind":"history","section":"history","keywords":"LK-20260720-reader-oriented-app-manuals-and-test-wrapper 2026-07-20 142 docs compatible App documentation Documentation validation Agent testing workflow Agent skill maintenance","text":"App manuals become reader-oriented and focused tests gain one wrapper id: LK-20260720-reader-oriented-app-manuals-and-test-wrapper date: 2026-07-20 sequence: 142 type: docs compatibility: compatible scope: App documentation scope: Documentation validation scope: Agent testing workflow scope: Agent skill maintenance Context Concrete App manuals repeated shared hover-help and runtime architecture contracts. The repetition displaced workflow and scientific content, became stale when the framework changed, and made every App page appear more implementation-oriented than user-oriented. Focused test execution also required agents to repeatedly assemble low-level runner arguments; omitting GUI inclusion could produce a zero-match selection that looked like a test problem. Decision and rationale Keep shared behavior in the App catalog and framework manual. Concrete App pages describe only their inputs, workflow, App-specific interactions, scientific semantics, outputs, recovery, programmatic surface, and limitations. Protect that boundary with a documentation guardrail. Provide one platform-independent MATLAB wrapper with explicit operations for listing a file's canonical test names, running an exact file, running a canonical class or method within its owning file, and running a suite. Keep broad final gates on the existing `buildtool` interface. Treat recurring reasoning, command construction, discovery, and retry cost as skill-maintenance signals. Improvements must describe durable concepts and semantic operations rather than one product version, App, transient failure, or current repository snapshot. Changes Removed repeated hover-help and Framework Compatibility boilerplate from all tracked App manuals. Rewrote project-state passages around user-visible persistence, recovery, source relinking, and recalculation rather than internal factories, callbacks, and schema implementation. Clarified the App-manual authoring contract and added a guardrail against reintroducing shared framework boilerplate. Added `runLabKitTestTarget.m` to the test-planner skill with automatic repository discovery, GUI inference for exact files and GUI suites, hidden figures, focused artifacts, and fail-on-zero-match behavior. Made exact canonical selectors resolve their unique owning test file, while retaining an explicit file constraint for ambiguous ownership. Made local parallel build tasks retain structured shard state while relaying concise human-readable heartbeats, clear stale transient status at worker startup, and print only failing worker logs instead of remaining silent and then dumping every shard log. Moved child-process orchestration out of `buildfile.m` into a MATLAB/Java runner shared by local macOS, Linux, and Windows, removing generated POSIX scripts and adding an independent ETA to each shard summary. Hosted CI remains single-process pending explicit concurrent-license evidence. Partitioned broad local workers by unique test-class owner file so each worker discovers only its assigned files instead of repeating full-tree discovery. Batched App path registration while keeping every setup call sensitive to newly added App entrypoints, added quiet discovery probes, and removed one unreferenced GUI assertion helper. Updated the skill to list canonical names before exact method reruns and to distinguish selection failures from passing evidence. Added a root agent rule to improve skills and scripts when reusable automation can remove recurring inference or retry cost. User and data impact App behavior, calculations, saved data, and exports are unchanged. Existing manual content about scientific meaning and recovery remains available with less implementation noise. The wrapper is an agent convenience over the official test runner and does not add another CI or public build interface. Compatibility and migration No additional migration applies beyond the compatibility information in the preceding impact section. Validation Documentation guardrails scan every concrete App manual for shared boilerplate. Documentation rendering and byte-for-byte site comparison cover all edited pages and this record. The wrapper lists and runs canonical GUI methods through the official runner, demonstrating automatic hidden-GUI selection. Test-runner profiling measured fresh full discovery before and after the path change at 5.83 and 4.82 seconds; path setup fell from 1.27 to 0.32 seconds. The retained rescan avoids a stale-cache failure when an App is added during a MATLAB session. Build contracts prove file partitions are disjoint, cover every selected test, accept deeply nested owning files, and preserve explicit failures for missing or ambiguous owners. Evidence The validation details above are the supporting evidence for this record. Known limitations and follow-up Continue reviewing App manuals when user-visible behavior changes; structural guardrails prevent known boilerplate but cannot judge scientific clarity."},{"title":"App tools and presentation controls become more deliberate","url":"history/records/2026/07/LK-20260720-app-tools-menu-and-screenshot-clipboard.html","kind":"history","section":"history","keywords":"LK-20260720-app-tools-menu-and-screenshot-clipboard 2026-07-20 141 feat compatible labkit.app App Framework All tracked Apps","text":"App tools and presentation controls become more deliberate id: LK-20260720-app-tools-menu-and-screenshot-clipboard date: 2026-07-20 sequence: 141 type: feat compatibility: compatible component: `labkit.app` | `1.1.0 -> 1.2.0` scope: App Framework scope: All tracked Apps Context Plot, Screenshot, Save State, and Load State appeared as separate root-level native menu items. Plot was a container while the other items executed immediately, so controls at the same visual level had inconsistent behavior and consumed unnecessary horizontal space. Screenshot also required a file dialog even when the user only needed an image for another application. Short status summaries consumed the same height as detail panels, and Apps could preserve plot zoom but had no declarative one-shot reset revision. Decision and rationale Install one framework-owned **Tools** root with purpose-based **Plots**, **Screenshot**, and conditional **Project State** submenus. Keep scientific workflow controls in the App layout while grouping domain-neutral native utilities predictably. Use MATLAB's existing `copygraphics` clipboard path so the capability remains platform-neutral and introduces no external runtime. Changes Moved plot utilities beneath **Tools > Plots**. Added **Tools > Screenshot > Copy to Clipboard** for the complete App surface and retained file export as **Save to File...**. Moved project persistence beneath **Tools > Project State** when the App owns a project document. Preserved existing executable action tags for compatibility with GUI automation and added stable tags for the new menu containers and clipboard action. Added a line-count hint for compact status summaries and a general plot-view revision that accepts renderer-fitted limits once while preserving user zoom during ordinary redraws. Updated the getting-started and framework manuals. User and data impact App calculations, project files, plots, and exports are unchanged. Existing action tags continue to identify save screenshot, save state, load state, and plot commands, but users now reach them through the Tools hierarchy. Clipboard copy uses the operating system clipboard and may be unavailable in a noninteractive MATLAB session. Compatibility and migration No additional migration applies beyond the compatibility information in the preceding impact section. Validation Hidden native-adapter GUI coverage verifies the menu hierarchy, labels, conditional Project State menu, stable action tags, and clipboard callback wiring. Focused framework tests validate the App SDK version and native runtime. Documentation rendering and consistency checks cover the updated manuals and history record. Evidence The validation details above are the supporting evidence for this record. Known limitations and follow-up Developer-led interactive checks should confirm clipboard image fidelity and native menu appearance on supported MATLAB desktop platforms."},{"title":"App validation no longer relies on sibling App paths","url":"history/records/2026/07/LK-20260717-isolated-app-validation.html","kind":"history","section":"history","keywords":"LK-20260717-isolated-app-validation 2026-07-17 128 test compatible Public App path isolation Changed-file validation routing GUI CI evaluation","text":"App validation no longer relies on sibling App paths id: LK-20260717-isolated-app-validation date: 2026-07-17 sequence: 128 type: test compatibility: compatible scope: Public App path isolation scope: Changed-file validation routing scope: GUI CI evaluation Context The ordinary public test setup adds every App entry folder so family and cross-App contract suites can run efficiently. That broad path can conceal an accidental dependency on a sibling App package. Static source scans rejected direct sibling calls, and individual Gait/private launch tests used isolated paths, but there was no uniform executable contract for every public App or automatic changed-file route to that contract. Decision and rationale Keep the convenient broad path for ordinary suites, but add one fast independent proof. For each public App, restore MATLAB's default path, add only the repository root and the owning App root, load its complete definition, check declared facade compatibility, and write its synthetic debug sample. Run this contract whenever public App source changes. Static call scanning and dynamic isolation cover different risks and remain separate. The former identifies the forbidden source reference; the latter proves metadata, framework requirements, and debug generation work in the same path shape as a single-App package. Changes Added one isolated-path contract covering all 20 public Apps. Routed every App source change to that contract in both conservative and fast changed-file plans. Added a planner regression so future routing changes cannot silently drop isolation coverage. Documented why independent private workspaces must run their own compatibility checks without inheriting public App roots. Evaluated, but did not add, a hidden-GUI job to every pull request. User and data impact There is no App or saved-data behavior change. A new sibling package dependency, stale facade requirement, incomplete definition, or broken debug sample now fails in a focused non-GUI contract instead of passing because all Apps happened to be on the developer's MATLAB path. Compatibility and migration No migration is required. Existing test commands remain unchanged; the changed-file planner adds the focused isolation selection automatically. Validation The all-App isolation contract completed in about 14 seconds locally. Existing changed-file evidence measured representative hidden image workflows at about 18 seconds each and a Gait hidden launch at about 30 seconds, before MATLAB startup and license acquisition. Since those synthetic GUI checks still do not prove native dialogs, pointer feel, or visual quality, ordinary CI keeps the fast non-GUI contract while App-specific GUI checks remain changed-file, scheduled, manual, and release validation. The private workspace's independent suite passes after removing public App roots from its runner path. Evidence [Testing and validation](../../../../development/maintain-and-release/testing.md) [Architecture](../../../../development/build-apps/architecture.md) [App development](../../../../development/build-apps/app-development.md) Known limitations and follow-up MATLAB process-global function caches cannot replace package-boundary source review, so the static sibling-call guard remains required. Hidden GUI tests remain bounded semantic checks rather than substitutes for manual interaction and visual assessment."},{"title":"Base-MATLAB image compatibility","url":"history/records/2026/07/LK-20260713-base-matlab-image-compatibility.html","kind":"history","section":"history","keywords":"LK-20260713-base-matlab-image-compatibility 2026-07-13 45 feat compatible labkit.image labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app Base-MATLAB image compatibility","text":"Base-MATLAB image compatibility id: LK-20260713-base-matlab-image-compatibility date: 2026-07-13 sequence: 45 type: feat compatibility: compatible component: `labkit.image` | `1.1.0 -> 1.2.0` component: `labkit_DICPostprocess_app` | `1.3.4 -> 1.3.5` component: `labkit_DICPreprocess_app` | `1.3.5 -> 1.3.6` component: `labkit_FocusStack_app` | `1.4.7 -> 1.4.8` component: `labkit_ImageEnhance_app` | `1.5.6 -> 1.5.7` component: `labkit_ImageMatch_app` | `1.5.6 -> 1.5.7` scope: Base-MATLAB image compatibility Context Several image workflows appeared toolbox-optional but still called Image Processing Toolbox functions for conversion, grayscale luminance, resizing, smoothing, alignment, or warping. Development machines with the toolbox hid those calls, so a nominally supported Base MATLAB installation could fail only after the user entered a particular workflow. Decision and rationale Own the essential image operations used by LabKit and make their Base MATLAB paths the tested behavior. Optional toolbox acceleration could remain only when the call was explicit, a repository-owned fallback existed, and parity tests protected the app-consumed result. Changes `labkit.image` `1.1.0 -> 1.2.0` `labkit_DICPreprocess_app` `1.3.5 -> 1.3.6` `labkit_DICPostprocess_app` `1.3.4 -> 1.3.5` `labkit_FocusStack_app` `1.4.7 -> 1.4.8` `labkit_ImageEnhance_app` `1.5.6 -> 1.5.7` `labkit_ImageMatch_app` `1.5.6 -> 1.5.7` Added `labkit.image.toDouble` and `labkit.image.toLuma`, and replaced hard Image Processing Toolbox calls in shared image facade code and image-app workflow paths with base-MATLAB implementations. DIC preprocessing now uses a toolbox-free phase-correlation translation path for automatic alignment and a base-MATLAB rigid warp for control-point alignment. DIC postprocessing, Focus Stack, Image Enhance, and Image Match now use app-local or facade-owned image normalization, resizing, smoothing, and luma helpers instead of requiring toolbox functions. Added a project hygiene guardrail that rejects unguarded toolbox image helper calls under `apps/` and `+labkit/`, while still allowing explicit optional toolbox paths with fallbacks. User and data impact DIC alignment and overlays, Focus Stack, Image Enhance, and Image Match could run without Image Processing Toolbox. Users with the toolbox retained compatible workflows, while CI now exercised the installation that previously failed late and silently. Compatibility and migration Existing app workflows and exported schemas are preserved. Optional toolbox acceleration paths remain allowed only when a base-MATLAB fallback is present. Validation The commit expanded DIC, Focus Stack, Image Enhance, Image Match, and image- facade unit suites and added `ToolboxDependencyGuardrailTest` to detect new unguarded calls. GUI layout tests covered the affected DIC workflows. The exact historical command was not recorded. Evidence Mainline commit `bcd5f51f`. Known limitations and follow-up Base MATLAB compatibility does not mean every optional accelerated algorithm is numerically identical by construction. Where a toolbox branch affects scientific values, representative parity and idempotency tests remain required until the repository-owned implementation fully replaces it."},{"title":"Batch Crop assigns state to workflow capabilities","url":"history/records/2026/07/LK-20260716-batch-crop-structure.html","kind":"history","section":"history","keywords":"LK-20260716-batch-crop-structure 2026-07-16 101 refactor compatible labkit_BatchImageCrop_app Image Measurement App structure","text":"Batch Crop assigns state to workflow capabilities id: LK-20260716-batch-crop-structure date: 2026-07-16 sequence: 101 type: refactor compatibility: compatible component: `labkit_BatchImageCrop_app` | `1.7.2 -> 1.7.3` scope: Image Measurement scope: App structure Context Batch Crop split static metadata across separate files, spread project creation, validation, migration, and session construction through a generic lifecycle package, and placed source decoding, crop-task operations, geometry, scale calibration, export planning, and transient caches together under `+appState`. The App also retained an unused scale-unit adapter and a startup callback whose only job duplicated the shared source-adjacent output-folder default. Decision and rationale Use the compact Runtime V2 definition and one project contract, then assign remaining helpers to the workflow capability that owns their meaning. Crop geometry, scale calibration, and export planning are real App complexity and remain App-owned; generic lifecycle and state buckets are structural debt and are removed. Changes Consolidated product metadata, version, requirements, layout, actions, presentation, renderers, and optional capabilities in `definition.m`. Concentrated durable creation, validation, and the version-1 upgrade in the single `projectSpec.m` entry; root `createSession.m` rebuilds transient state and lazily loads the selected source. Replaced embedded image data and direct path fields with canonical source records and `sourceId` task references. Assigned file reconstruction to `+sourceFiles`, task operations to `+cropTasks`, coordinate and cache behavior to `+cropGeometry`, calibration semantics to `+scaleCalibration`, and export state to `+resultFiles`. Removed the generic lifecycle/state packages, separate metadata files, redundant startup callback, and unused scale-unit wrapper. User and data impact Multiple crop tasks per source, draggable and resizable ROIs, zoom-preserving preview edits, rotation, edge-continuous padding, pixel and physical crop modes, per-source calibration, scale bars, manifests, and exports keep their existing behavior. Empty launch no longer computes an output folder; importing sources still selects the source-adjacent default. Developers can now find each calculation and state transition under its owning workflow concept without learning a generic App state package. Compatibility and migration Version-1 saved projects upgrade automatically to schema version 2. The migration discards reconstructible embedded pixels, creates portable source records for legacy paths, and preserves crop-task settings. Runtime source reconciliation handles moved or missing required files. Validation Focused unit tests cover project creation, validation and migration, source reading, crop geometry, scale planning, export planning, and manifest output. The hidden GUI workflow loads an image, manipulates the crop workflow, and exports a synthetic crop through the real Runtime callbacks. Evidence [Batch Image Crop](../../../../apps/image-measurement/batch-crop/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [Image Library](../../../../libraries/image/README.md) Known limitations and follow-up Automated GUI tests do not replace manual judgment of ROI pointer feel, resampling quality, scale-reference placement, or export suitability for a particular quantitative workflow. Other Apps that still use generic lifecycle or state packages remain scheduled for the same ownership review."},{"title":"Batch Crop file workflow feedback","url":"history/records/2026/06/LK-20260628-batch-crop-file-workflow-feedback.html","kind":"history","section":"history","keywords":"LK-20260628-batch-crop-file-workflow-feedback 2026-06-28 14 feat compatible labkit.ui labkit_BatchImageCrop_app Batch Crop file workflow feedback","text":"Batch Crop file workflow feedback id: LK-20260628-batch-crop-file-workflow-feedback date: 2026-06-28 sequence: 14 type: feat compatibility: compatible component: `labkit.ui` | `3.0.1 -> 3.1.0` component: `labkit_BatchImageCrop_app` | `1.2.0 -> 1.3.0` scope: Batch Crop file workflow feedback Context In a multi-file Batch Crop session, the window and preview did not consistently show which list item supplied the current image and crop settings. Decision and rationale Make the selected file part of the shared window-title context and update Batch Crop feedback whenever selection changes. Keep the title derived from the file panel so the app does not maintain a second selection label. Changes `labkit.ui` `3.0.1 -> 3.1.0` Batch Crop `1.2.0 -> 1.3.0` Added selected-file title context. Improved Batch Crop file workflow feedback. User and data impact The active filename became visible while reviewing or editing a crop task, reducing the chance of applying settings to the wrong image. Crop geometry and exported data were unchanged. Compatibility and migration Batch Crop tasks and exports kept their existing format. The change affected file-selection context and feedback in the window only. Validation Commit `61e8edd3` updated shared title-context and Batch Crop GUI workflow coverage. Evidence Main commit `61e8edd3`. Known limitations and follow-up Later file-panel work extended the same title context and append behavior to the rest of the app fleet."},{"title":"Binding-only controls and default resource cleanup","url":"history/records/2026/07/LK-20260717-binding-and-resource-defaults.html","kind":"history","section":"history","keywords":"LK-20260717-binding-and-resource-defaults 2026-07-17 122 refactor compatible labkit.ui labkit_VideoMarker_app Runtime V2 action registration Runtime V2 resource ownership","text":"Binding-only controls and default resource cleanup id: LK-20260717-binding-and-resource-defaults date: 2026-07-17 sequence: 122 type: refactor compatibility: compatible component: `labkit.ui` | `7.4.5 -> 7.4.6` component: `labkit_VideoMarker_app` | `1.5.4 -> 1.5.5` scope: Runtime V2 action registration scope: Runtime V2 resource ownership Context Runtime V2 already supported controls whose complete behavior is writing one bound state path, but Video Marker still registered an empty action for its skeleton-preset selector. The private resource registry also had a default cleanup policy, while the injected App service required every call to supply a fourth cleanup function. Video Marker therefore kept a second empty function for its plain decoded-video resource. Decision and rationale Use the existing binding-only contract for state-only controls and expose the resource registry's existing default cleanup through the injected service. Apps should declare an action only when a user event has workflow behavior beyond committing the bound value. Plain structs and values require no App-owned cleanup placeholder. Changes Removed Video Marker's empty skeleton-preset change action and left the dropdown as a direct session binding. Made the injected `services.resources.set(scope,id,value)` form select the Runtime's default cleanup, while retaining the optional fourth custom cleanup function. Removed Video Marker's empty video-resource cleanup function. Added Runtime GUI coverage for binding-only state commits and resources registered without a custom cleanup. User and data impact There is no workflow, scientific, project-data, or saved-file change. Selecting a skeleton preset still updates the session immediately, and **Use preset** still performs the only durable skeleton edit. Video cache replacement and session cleanup retain the same observable behavior. Compatibility and migration The change is source-compatible. Existing four-argument resource registration continues to use the supplied cleanup function. No project migration is required. Validation The focused Runtime V2 GUI test exercises both service forms and proves that a binding without `Event` commits state without invoking an App action. Video Marker structure and targeted behavior tests cover the simplified definition. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) documents bound controls and injected resource ownership. [Video Marker](../../../../apps/image-measurement/video-marker/README.md) describes the preset and decoded-video resource behavior. Known limitations and follow-up Other bound events still require App actions when they normalize values, invalidate results, update previews, or log workflow changes. They should be reviewed by behavior rather than removed merely because their handlers are short."},{"title":"CIC consolidates its project contract without losing lazy loading","url":"history/records/2026/07/LK-20260716-cic-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-cic-project-spec 2026-07-16 87 refactor compatible labkit_CIC_app Electrochemistry Project lifecycle","text":"CIC consolidates its project contract without losing lazy loading id: LK-20260716-cic-project-spec date: 2026-07-16 sequence: 87 type: refactor compatibility: compatible component: `labkit_CIC_app` | `1.4.1 -> 1.4.2` scope: Electrochemistry scope: Project lifecycle Context CIC split static metadata across three files and its first-version project across a generic lifecycle package. Its session factory also encodes an important performance policy: restore only the first source for preview rather than parsing an entire large batch. Decision and rationale Consolidate product metadata in `definition.m` and durable schema behavior in `projectSpec.m`. Keep `createSession.m` separate and explicit because lazy source decoding is real transient reconstruction and a user-visible performance boundary, not lifecycle boilerplate. Changes Moved command metadata, version, update date, and requirements into the definition. Consolidated project defaults and validation behind one project spec. Moved lazy preview restoration to one package-root session factory. Removed separate metadata files and the generic lifecycle package. Kept pulse detection, CIC formulas, units, limits, plots, and exports unchanged. User and data impact Launch, source selection, large-batch behavior, computation, save/load, and CSV exports behave unchanged. The App structure is smaller while the reason for its lazy session factory is now documented next to the code. Compatibility and migration The project remains version 1 with identical fields, defaults, validation, and source records. Existing CIC projects require no migration. Validation Unit tests cover the project contract, CIC calculation, units, failed rows, CSV schema, and presentation. The hidden GUI workflow covers real launch, source selection, calculation, save/load, and export through Runtime V2. Evidence [CIC](../../../../apps/electrochemistry/cic/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up The session currently reads `reference.originalPath` directly. That internal portable-reference representation will be replaced by a simple framework source-path service across all Apps rather than patched only in CIC."},{"title":"CIC uses Runtime-owned source and workflow mechanics","url":"history/records/2026/07/LK-20260716-cic-runtime-source-reconciliation.html","kind":"history","section":"history","keywords":"LK-20260716-cic-runtime-source-reconciliation 2026-07-16 112 refactor compatible labkit_CIC_app Electrochemistry App structure Runtime adoption","text":"CIC uses Runtime-owned source and workflow mechanics id: LK-20260716-cic-runtime-source-reconciliation date: 2026-07-16 sequence: 112 type: refactor compatibility: compatible component: `labkit_CIC_app` | `1.4.3 -> 1.4.4` scope: Electrochemistry scope: App structure scope: Runtime adoption Context CIC intentionally registers paths before decoding them so large batches remain lazy, but it still generated, appended, and deleted portable source records in App code. It also wrote directly to `session.workflow.logLines`, requiring its session factory to reproduce Runtime-owned empty workflow and view buckets. Those details increased the amount of framework structure an App maintainer had to understand without expressing CIC analysis behavior. Decision and rationale CIC continues to own the ordered lazy path set, current-index policy, deferred decoding, scientific options, and result workflow. It now passes that ordered path set to `services.project.reconcileSources` after add, removal, and clear operations. Runtime preserves matching identities and allocates new unique ones. Analysis messages use `services.workflow.log`, the same service as other workflow messages. `createSession` returns only CIC-specific selection and decoded-cache state; Runtime creates missing transient buckets before actions run. Changes Removed App-local source-ID generation and source append helpers. Reconciled registered paths through the Runtime project service. Routed analysis messages through the Runtime workflow service. Removed empty workflow and view boilerplate from `createSession`. Added GUI checks for stable and unique identities across batch add, save, reopen, removal, and re-addition. Advanced the CIC App version to 1.4.4. User and data impact Lazy decoding, file order, selected preview, analysis values, plots, exports, logs, and project files retain their behavior. Source identities remain stable for retained files and collision-free for newly registered files. Scientific calculations and output schemas are unchanged. Compatibility and migration The current project payload remains version 1 and needs no migration. Existing source records and their identities are preserved when reopened. Validation The CIC hidden GUI workflow covers three-source lazy registration, selection, whole-batch recomputation, export, save, clear, reopen, remove, re-add, source identity, viewport refresh, and final clear. Focused calculation/view, App structure, version, documentation, and history tests cover the surrounding contracts. Evidence [Charge-Injection Capacity](../../../../apps/electrochemistry/cic/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Development](../../../../development/build-apps/app-development.md) Known limitations and follow-up CSC and VT Resistance still own similar source registration helpers. Their result indexing and lazy-load behavior must be checked independently before adopting the Runtime service."},{"title":"CSC consolidates its product and project contracts","url":"history/records/2026/07/LK-20260716-csc-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-csc-project-spec 2026-07-16 88 refactor compatible labkit_CSC_app Electrochemistry Project lifecycle","text":"CSC consolidates its product and project contracts id: LK-20260716-csc-project-spec date: 2026-07-16 sequence: 88 type: refactor compatibility: compatible component: `labkit_CSC_app` | `1.4.1 -> 1.4.2` scope: Electrochemistry scope: Project lifecycle Context CSC split product metadata across three files and its durable schema across a generic lifecycle package even though it has no historical payload migration. The additional entry points did not own distinct electrochemical behavior. Decision and rationale Make `definition.m` the complete product declaration and `projectSpec.m` the sole durable-schema entry. Keep `createSession.m` explicit because reloading CV/CT curves and restoring file/cycle selection is genuine transient work. Changes Consolidated command metadata, version, update date, and requirements in the definition. Consolidated project defaults and validation behind one project spec. Moved decoded curve and selection restoration to a package-root session factory. Removed separate metadata files and the generic lifecycle package. Kept integration formulas, sign splitting, scan-rate handling, area normalization, plots, and export schemas unchanged. User and data impact Launch, source and cycle selection, save/load, calculations, plots, and both export paths behave unchanged. The durable contract is now readable in one place without hiding scientific behavior in the framework. Compatibility and migration The project remains version 1 with identical fields, defaults, validation, and source records. Existing CSC projects require no migration. Validation Unit tests cover CT/CV calculations, edge-cycle policy, normalization, result tables, export schemas, project/session contracts, and presentation. The hidden GUI workflow covers real launch, file/cycle selection, calculation, save/load, plot overlays, and exports. Evidence [CSC](../../../../apps/electrochemistry/csc/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Decoded source restoration still reaches into portable-reference internals. That cross-App framework boundary remains scheduled for one shared source-path service rather than an App-specific wrapper."},{"title":"CSC delegates decoded-source identity to Runtime V2","url":"history/records/2026/07/LK-20260716-csc-runtime-source-reconciliation.html","kind":"history","section":"history","keywords":"LK-20260716-csc-runtime-source-reconciliation 2026-07-16 113 refactor compatible labkit_CSC_app Electrochemistry App structure Runtime adoption","text":"CSC delegates decoded-source identity to Runtime V2 id: LK-20260716-csc-runtime-source-reconciliation date: 2026-07-16 sequence: 113 type: refactor compatibility: compatible component: `labkit_CSC_app` | `1.4.3 -> 1.4.4` scope: Electrochemistry scope: App structure scope: Runtime adoption Context CSC eagerly decodes accepted CV/CT files and keeps decoded item order aligned with durable source order. Its action file nevertheless generated source IDs, appended records, and deleted records by index. The session factory also declared empty workflow and view buckets already guaranteed by Runtime V2. Those mechanics were framework persistence responsibilities rather than CSC curve-selection or scientific behavior. Decision and rationale Continue using successfully decoded item order as the App-owned source order, then reconcile durable records through `services.project.reconcileSources` after additions, removals, and clearing. Runtime preserves records for retained paths and allocates collision-free IDs for new paths. CSC continues to own decoding, active file and curve selection, plot defaults, calculation, exports, and failure messages. Return only the CSC-specific selection fields and decoded item cache from `createSession`; Runtime supplies missing transient buckets. Changes Removed App-local source-ID generation and source append helpers. Reconciled source records from the decoded item list. Replaced the growing failure array with a single first-failure record while retaining per-file workflow logs. Removed empty workflow and view session boilerplate. Added GUI checks for canonical buckets and stable, unique identities across add, save, reopen, removal, and re-addition. Advanced the CSC App version to 1.4.4. User and data impact File order, selected curve, plot resets, CSC calculations, reload, exports, logs, and saved projects retain their behavior. Retained source identities no longer depend on App-local append/delete logic. Scientific values and result schemas are unchanged. Compatibility and migration The current project payload remains version 1 and needs no migration. Existing portable records retain their IDs when the corresponding paths remain loaded. Validation The CSC hidden GUI workflow covers two-file decoding, file and cycle selection, plot changes, calculation display, export, save, clear, reopen, remove, re-add, source identity, and final plot clearing. Focused CSC calculation/view and repository contract tests cover the remaining behavior. Evidence [Charge-Storage Capacity](../../../../apps/electrochemistry/csc/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Development](../../../../development/build-apps/app-development.md) Known limitations and follow-up VT Resistance remains the last electrochem batch App with the same local source-ID and append pattern and requires a separate behavior audit."},{"title":"CSC export and viewport policy","url":"history/records/2026/07/LK-20260703-csc-export-and-viewport-policy.html","kind":"history","section":"history","keywords":"LK-20260703-csc-export-and-viewport-policy 2026-07-03 35 feat compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app CSC export and viewport policy","text":"CSC export and viewport policy id: LK-20260703-csc-export-and-viewport-policy date: 2026-07-03 sequence: 35 type: feat compatibility: compatible component: `labkit.ui` | `4.0.0 -> 4.1.0` component: `labkit_DICPostprocess_app` | `1.3.2 -> 1.3.3` component: `labkit_DICPreprocess_app` | `1.3.2 -> 1.3.3` component: `labkit_ChronoOverlay_app` | `1.3.2 -> 1.3.3` component: `labkit_CIC_app` | `1.3.4 -> 1.3.5` component: `labkit_CSC_app` | `1.3.4 -> 1.3.6` component: `labkit_EIS_app` | `1.3.2 -> 1.3.3` component: `labkit_VTResistance_app` | `1.3.4 -> 1.3.5` component: `labkit_BatchImageCrop_app` | `1.6.4 -> 1.6.5` component: `labkit_CurvatureMeasurement_app` | `1.3.2 -> 1.3.3` component: `labkit_FLIRThermal_app` | `1.2.3 -> 1.2.4` component: `labkit_FocusStack_app` | `1.4.3 -> 1.4.4` component: `labkit_ImageEnhance_app` | `1.5.3 -> 1.5.4` component: `labkit_ImageMatch_app` | `1.5.3 -> 1.5.4` component: `labkit_NerveResponseAnalysis_app` | `1.3.2 -> 1.3.3` component: `labkit_ResponseReviewStats_app` | `1.3.2 -> 1.3.3` component: `labkit_RHSPreview_app` | `1.3.2 -> 1.3.3` component: `labkit_ECGPrint_app` | `1.3.3 -> 1.3.4` scope: CSC export and viewport policy Context CSC could export the selected cycle, but comparing activation and stability across a recording required all cycles in one dataset. In parallel, app layouts made their own assumptions about minimum window size and scrollable content, so the same control panel could behave differently in a small viewport. Decision and rationale Add an explicit all-cycle CSC export without changing the existing selected- cycle result. Define viewport behavior in the UI contract so each app declares its content needs while the framework decides when scrolling or minimum sizing is necessary. Changes `labkit.ui` `4.0.0 -> 4.1.0` All supported apps received aligned patch bumps. Added CSC all-cycle export. Added viewport policy support and aligned app contracts with the UI 4.x line. User and data impact CSC users could export every cycle for downstream comparison while retaining the existing focused export. Across the workbench, small windows followed one scrolling and sizing policy instead of clipping controls according to the app that happened to create them. Compatibility and migration The selected-cycle CSC export remained available and the all-cycle table was a new option. Existing app definitions inherited the default viewport behavior until they declared more specific needs. Validation Commit `a69829c6` added a dedicated CSC export suite, extended the CSC GUI layout test, and added workbench viewport coverage. Evidence Main commit `a69829c6`. Known limitations and follow-up All-cycle CSV output was a separate export choice rather than a new session format. Later CSC work refined column naming and voltage/current organization."},{"title":"Callback-safe native layout synchronization","url":"history/records/2026/07/LK-20260721-callback-safe-layout-synchronization.html","kind":"history","section":"history","keywords":"LK-20260721-callback-safe-layout-synchronization 2026-07-21 152 fix compatible labkit.app App Framework Hidden GUI validation","text":"Callback-safe native layout synchronization id: LK-20260721-callback-safe-layout-synchronization date: 2026-07-21 sequence: 152 type: fix compatibility: compatible component: `labkit.app` | `1.2.3 -> 1.2.4` scope: App Framework scope: Hidden GUI validation Context The App SDK synchronizes native layout before calculating pixel-dependent plot geometry and while publishing busy, startup, close-prompt, and popout views. A full MATLAB `drawnow` also executes pending callbacks, which can introduce unrelated UI or timer work during those internal rendering operations. Decision and rationale Keep the required native graphics synchronization, but defer callbacks while the framework is calculating or publishing its own view. Long-running interactive launcher and profiler waits continue to process callbacks so users can close their windows. Changes Use callback-deferred graphics updates for equal-scale fitting and fixed-aspect preview geometry. Use callback-deferred updates while the native App runtime publishes busy, startup, failure, close-prompt, and popout-style state. Verify equal-scale EIS fitting, preview-canvas layout, and native runtime lifecycle behavior with hidden GUI tests. User and data impact Apps retain the same layouts and fitted limits while framework rendering no longer processes unrelated pending callbacks mid-operation. Projects, source records, results, and exports are unchanged. Compatibility and migration This compatible patch does not alter the public API or require project/result migration. Validation Focused hidden-GUI EIS equal-axis, Figure Studio preview, and native adapter lifecycle checks pass locally. The complete platform matrix remains the final validation for native GUI scheduling behavior. Evidence MATLAB documents that full `drawnow` both updates figures and processes pending callbacks, while the `nocallbacks` forms defer those callbacks. The framework uses callback-deferred synchronization only where it must read settled native geometry or publish internal view state. Known limitations and follow-up Automated hidden GUI checks do not substitute for manual visual and interaction assessment on supported MATLAB desktop platforms."},{"title":"Canonical role-based source collections","url":"history/records/2026/07/LK-20260716-canonical-role-based-sources.html","kind":"history","section":"history","keywords":"LK-20260716-canonical-role-based-sources 2026-07-16 73 refactor compatible labkit_RHSPreview_app labkit_NerveResponseAnalysis_app project payload schema source roles and relinking","text":"Canonical role-based source collections id: LK-20260716-canonical-role-based-sources date: 2026-07-16 sequence: 73 type: refactor compatibility: compatible component: `labkit_RHSPreview_app` | `1.4.0 -> 1.4.1` component: `labkit_NerveResponseAnalysis_app` | `1.4.0 -> 1.4.1` scope: project payload schema scope: source roles and relinking Context RHS Preview and Nerve Response Analysis stored external files in separate app-specific fields such as `rhsSource`, `filterSources`, and `protocolSource`. The records already carried explicit roles, but Runtime V2 could only discover the canonical `project.inputs.sources` collection during portable save/load and missing-file relinking. Decision and rationale Store every external dependency in one canonical collection and select records by their app-owned role. The framework remains domain-neutral, while each app continues to distinguish preview recordings, filter recordings, filter JSON, and optional protocols without duplicating persistence mechanics. Changes Advanced both project payload schemas from version 1 to version 2. Added ordered migrations that combine the former role-specific fields without changing source record contents or order. Added app-local role selection and replacement operations used consistently by lifecycle creation, actions, presenters, exports, and validation. Kept at most one primary recording/protocol per relevant app while allowing RHS Preview to retain an ordered collection of filter recordings. User and data impact Project reopen, result provenance, and future missing-file recovery can now see all selected dependencies. Preview, filtering, event detection, CAP metrics, and output formats are unchanged. Compatibility and migration Existing version 1 payloads remain readable and preserve every source record. The old fields are removed only from the migrated in-memory project; saving writes the version 2 canonical collection. Validation Focused unit tests verify role-preserving migrations and project versions. Focused GUI workflows verify RHS indexing, multiple filter-file management, project save/reopen, filter analysis, export, and transient cache rebuilding. Evidence [RHS Preview](../../../../apps/neurophysiology/rhs-preview/README.md) documents its three source roles. [Nerve Response Analysis](../../../../apps/neurophysiology/nerve-response-analysis/README.md) documents filter/protocol restoration and relinking. [App Framework](../../../../framework/README.md) defines the canonical project source collection. Known limitations and follow-up This change makes every source discoverable but does not yet rebase relative paths at the final project save destination. That framework serialization change is tracked as the next persistence batch."},{"title":"Canonical single-source app projects","url":"history/records/2026/07/LK-20260716-canonical-single-source-projects.html","kind":"history","section":"history","keywords":"LK-20260716-canonical-single-source-projects 2026-07-16 72 refactor compatible labkit_GaitAnalysis_app labkit_CurvatureMeasurement_app labkit_ECGPrint_app labkit_ResponseReviewStats_app project payload schema source relinking","text":"Canonical single-source app projects id: LK-20260716-canonical-single-source-projects date: 2026-07-16 sequence: 72 type: refactor compatibility: compatible component: `labkit_GaitAnalysis_app` | `2.0.0 -> 2.0.1` component: `labkit_CurvatureMeasurement_app` | `1.4.0 -> 1.4.1` component: `labkit_ECGPrint_app` | `1.4.0 -> 1.4.1` component: `labkit_ResponseReviewStats_app` | `1.4.0 -> 1.4.1` scope: project payload schema scope: source relinking Context The Runtime V2 project contract discovers external files through the `project.inputs.sources` collection. Four single-source apps instead stored their record under a singular `project.inputs.source` field. Their own actions could open that path, but framework save/load relinking could not discover it. Decision and rationale Use the same canonical source collection for every single-source app. The plural field is a collection even when it currently contains zero or one record, so persistence and relinking do not need app-specific field knowledge. Changes Moved Gait Analysis, Curvature Measurement, ECG Print, and Response Review Stats source ownership to `project.inputs.sources`. Advanced each payload schema by one version and added the corresponding ordered migration. Updated action, presenter, session, validation, export, and manual references to the canonical collection. Corrected the Gait family overview to describe its current strict Video Marker project input instead of retired generic MAT/table inputs. User and data impact New saves expose their source records to the common portable-project resolver. Scientific calculations, UI choices, annotations, parameters, and result values are unchanged. Compatibility and migration Existing payloads remain readable. Loading copies the former singular field to the canonical collection and removes the retired field. A later save writes the new payload version; source record contents are not transformed. Validation Focused unit tests verify each field migration, current project version, and existing calculations. Focused hidden-GUI tests verify that each app still launches and follows its source workflow with the renamed durable field. Evidence [App Framework](../../../../framework/README.md) defines the canonical source collection used by project persistence. [Gait Analysis](../../../../apps/gait/gait-analysis/README.md), [Curvature Measurement](../../../../apps/image-measurement/curvature/README.md), [ECG Print](../../../../apps/wearable/ecg-print/README.md), and [Response Review Stats](../../../../apps/neurophysiology/response-review-stats/README.md) describe their upgraded project behavior. Known limitations and follow-up This record covers single-source apps. Multi-role neurophysiology projects are audited separately because preserving source roles requires a richer migration than renaming one field."},{"title":"Chrono Overlay adopts one version-aware project migration entry","url":"history/records/2026/07/LK-20260716-chrono-overlay-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-chrono-overlay-project-spec 2026-07-16 86 refactor compatible labkit_ChronoOverlay_app Electrochemistry Project lifecycle","text":"Chrono Overlay adopts one version-aware project migration entry id: LK-20260716-chrono-overlay-project-spec date: 2026-07-16 sequence: 86 type: refactor compatibility: compatible component: `labkit_ChronoOverlay_app` | `1.4.1 -> 1.4.2` scope: Electrochemistry scope: Project lifecycle Context Chrono Overlay split product metadata across three files and represented its only payload upgrade as a separately named `migrateProjectV1ToV2.m` file in a generic lifecycle package. Adding another schema version would have added yet another file and exposed migration sequencing to the App definition. Decision and rationale Make `definition.m` the product declaration and `projectSpec.m` the sole durable-schema entry. Its `Migrate(project, fromVersion)` callback owns App semantics for one version step; Runtime V2 owns the loop, version increment, validation after every step, and unsupported-envelope handling. Changes Consolidated project creation, validation, and migration in one project spec. Replaced the per-version migration file with one version-aware local function. Moved transient DTA reconstruction to a package-root session factory. Removed separate requirements, version, and generic lifecycle files. Kept DTA parsing, pulse-gap alignment, interpolation, plots, and exports unchanged. User and data impact Launch, plotting, save/load, v1 project upgrade, and CSV export behavior remain unchanged. Maintainers now add future schema cases in one ordered migration entry instead of editing both definition wiring and file inventories. Compatibility and migration Version-1 payloads still remove the obsolete decoded `inputs.items` field so portable source records remain the only durable input. Version-2 payloads are unchanged and need no migration. Validation Unit tests call the new migration entry with a synthetic v1 payload and verify validation, session reconstruction, pulse alignment, interpolation, and presenter output. The hidden GUI workflow covers real launch, source loading, plotting, and export through the consolidated definition. Evidence [Chrono Overlay](../../../../apps/electrochemistry/chrono-overlay/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Only v1-to-v2 is currently required. Future cases remain App-owned in the same function; they must not bypass the framework's stepwise validation loop."},{"title":"Chrono Overlay removes App-owned source identity bookkeeping","url":"history/records/2026/07/LK-20260716-chrono-runtime-source-reconciliation.html","kind":"history","section":"history","keywords":"LK-20260716-chrono-runtime-source-reconciliation 2026-07-16 111 fix compatible labkit_ChronoOverlay_app Electrochemistry App structure Project identity","text":"Chrono Overlay removes App-owned source identity bookkeeping id: LK-20260716-chrono-runtime-source-reconciliation date: 2026-07-16 sequence: 111 type: fix compatibility: compatible component: `labkit_ChronoOverlay_app` | `1.4.3 -> 1.4.4` scope: Electrochemistry scope: App structure scope: Project identity Context Chrono Overlay generated a new source ID from the current record count. After removing an earlier source, adding another file could therefore reuse an ID still owned by a retained record. Runtime validation correctly rejects duplicate IDs, but the App should not have been maintaining this persistence invariant itself. The App also duplicated source append/removal helpers and empty transient workflow/view buckets already supplied by Runtime V2. Decision and rationale After every successful add, removal, or clear operation, derive the ordered path list from the decoded items and delegate durable-record reconciliation to `services.project.reconcileSources`. Chrono Overlay continues to own decoding, pulse-gap alignment, item order, selection, logs, and failure wording. Runtime owns stable identity reuse and collision-free allocation. Only App-specific selection and decoded cache data are returned by `createSession`; Runtime canonicalizes the remaining transient buckets. Changes Removed App-local source record append, removal, and count-based ID logic. Reconciled source records from the accepted decoded item order. Removed empty workflow and view boilerplate from the session factory. Replaced the dynamically growing failure list with one first-failure record while retaining per-file log messages. Added a GUI regression sequence that removes the first of two sources, adds it again, checks unique IDs, saves, clears, and reopens the project. Advanced the Chrono Overlay App version to 1.4.4. User and data impact Normal file loading, ordering, selection, plots, exports, and saved project payloads retain their behavior. The remove-then-add sequence no longer risks a duplicate source ID and failed callback. Persistence IDs remain internal and do not change curve values or scientific output. Compatibility and migration The current payload remains version 2 and no new migration is needed. Existing records retain their IDs when their paths remain in the project. Validation The Chrono Overlay hidden GUI workflow covers two-file loading, selection, remove and re-add, unique identity, export, save, clear, reopen, option redraw, and final plot clearing. Focused unit, structure, version, documentation, and history tests protect the calculation and product contracts. Evidence [Chrono Overlay](../../../../apps/electrochemistry/chrono-overlay/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Development](../../../../development/build-apps/app-development.md) Known limitations and follow-up CIC, CSC, and VT Resistance still have equivalent App-local source identity helpers and require their own ordering and behavior audits before conversion."},{"title":"Clean-room cross-platform CI","url":"history/records/2026/07/LK-20260717-clean-room-cross-platform-ci.html","kind":"history","section":"history","keywords":"LK-20260717-clean-room-cross-platform-ci 2026-07-17 131 ci compatible project validation and release automation","text":"Clean-room cross-platform CI id: LK-20260717-clean-room-cross-platform-ci date: 2026-07-17 sequence: 131 type: ci compatibility: compatible scope: project validation and release automation Context The previous MATLAB workflow combined ordinary CI, scheduled reports, release validation, and raw tag creation. Its optional Base MATLAB job also mixed static source checks with installed-product dependency analysis, even though that analysis can only report products present on the runner. The design made it difficult to tell which evidence was required and did not exercise every candidate outside the developer's operating system. Decision and rationale Make a Toolbox-free MATLAB installation the baseline for all required CI behavior. Let one CI workflow run complete headless and hidden-GUI tasks on Linux, macOS, and Windows. Keep coverage as an explicit local report. Release creation remains a developer-initiated process after manual App validation, requires a successful main-push CI run for the exact commit, and stops at a draft for final human review. This directly tests the promised runtime instead of trying to infer the same fact from a runner with optional products installed. Changes Replaced the monolithic MATLAB workflow with one ordinary/reusable CI workflow and one manual release workflow. Made cross-platform Base MATLAB headless and hidden-GUI validation mandatory for pull requests and main pushes, and required exact same-commit CI evidence before release. Removed the installed-product dependency-analysis task and all CI Toolbox installation. Kept static known-Toolbox call detection and representative shadowed-helper workflows inside the ordinary headless suite. Kept coverage out of CI because it has no failure threshold and repeats the non-GUI tests; maintainers can still request the local report explicitly. Replaced raw Git-ref creation with a validated annotated tag, tag-blob launcher staging, remote asset verification, and a draft GitHub Release. User and data impact No App runtime, calculation, project, or saved-data behavior changes. CI may now expose operating-system, path, case-sensitivity, layout, or missing- dependency failures that a configured development machine did not reveal. Compatibility and migration Maintainers should use `Continuous Integration` for required checks, `buildtool coverage` for an on-demand local report, and the manual `Release` workflow only after interactive App validation. The retired `buildtool baseMatlab` task has no compatibility alias because clean Base MATLAB execution is now the environment of every required build task rather than a separate partial check. Validation The CI policy contract checks trigger separation, read-only ordinary permissions, three-platform matrices, absence of `products:` installation, public build-task use, timeouts, diagnostics, exact-sha CI evidence, manual release confirmation, tag-blob asset generation, and draft-only publication. Build-task and Toolbox guardrails verify the simplified catalog and retained static/fallback checks. Evidence `.github/workflows/ci.yml` and `release.yml` define the executable pipeline. `tests/cases/contract/project/ci/CiValidationPolicyGuardrailTest.m` protects the new boundaries. Known limitations and follow-up Hidden GUI tests cannot drive native dialogs or judge visual and pointer quality. Developer-led manual App testing therefore remains mandatory before starting a release. CI also detects only Toolbox calls reached by tests or covered by the maintained static-call set; temporary product use still needs its declared fallback, idempotency, and parity evidence."},{"title":"Close guards and caught-exception diagnostics","url":"history/records/2026/06/LK-20260630-close-guards-and-caught-exception-diagnostics.html","kind":"history","section":"history","keywords":"LK-20260630-close-guards-and-caught-exception-diagnostics 2026-06-30 21 feat compatible labkit.ui labkit_DICPostprocess_app labkit_BatchImageCrop_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FocusStack_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app Close guards and caught-exception diagnostics","text":"Close guards and caught-exception diagnostics id: LK-20260630-close-guards-and-caught-exception-diagnostics date: 2026-06-30 sequence: 21 type: feat compatibility: compatible component: `labkit.ui` | `3.2.6 -> 3.2.7` component: `labkit_DICPostprocess_app` | `1.2.1 -> 1.2.2` component: `labkit_BatchImageCrop_app` | `1.3.4 -> 1.3.5` component: `labkit_BatchImageCrop_app` | `1.3.5 -> 1.3.6` component: `labkit_CurvatureMeasurement_app` | `1.2.1 -> 1.2.2` component: `labkit_FocusStack_app` | `1.2.2 -> 1.2.3` component: `labkit_FocusStack_app` | `1.2.3 -> 1.2.4` component: `labkit_ImageEnhance_app` | `1.3.2 -> 1.3.3` component: `labkit_ImageMatch_app` | `1.3.2 -> 1.3.3` component: `labkit_ImageMatch_app` | `1.3.3 -> 1.3.4` component: `labkit_NerveResponseAnalysis_app` | `1.2.3 -> 1.2.4` component: `labkit_ResponseReviewStats_app` | `1.2.2 -> 1.2.3` component: `labkit_RHSPreview_app` | `1.2.1 -> 1.2.2` component: `labkit_ECGPrint_app` | `1.2.0 -> 1.2.1` scope: Close guards and caught-exception diagnostics Context Many app callbacks caught an exception, showed its message, and returned. That protected the UI but discarded the stack and callback context needed to diagnose the failure. Image apps also tracked unsaved or incomplete work in slightly different ways when deciding whether a window could close. Decision and rationale Report caught exceptions to the existing debug trace before presenting the user-facing error, and promote the file-index and close-guard mechanics that were shared by several image apps. Preserve app ownership of what counts as dirty or incomplete work. Changes `labkit.ui` `3.2.6 -> 3.2.7` DIC, Batch Crop, Curvature, Focus Stack, Image Match, neurophysiology apps, and ECG Print patch bumped for diagnostics or close-guard work. Reported caught app-runner exceptions through framework debug diagnostics. Promoted file-entry index helpers. Connected dirty/incomplete workflow state to close guards. User and data impact An app could still recover from a failed load, calculation, or export, while its debug report retained the exception evidence. Closing an image workflow with unfinished state produced a consistent warning instead of silently discarding work. Scientific results and saved schemas were unchanged. Compatibility and migration Existing app state and result files remained valid. Closing an incomplete workflow gained an additional confirmation, and debug reports gained exception details. Validation The exception-reporting commit expanded app/library compatibility checks across the affected runners. The close-guard commit added public-surface and compatibility coverage for promoted file indices and app close behavior. Exact historical commands were not recorded. Evidence Main commits `c0028a81` and `a81853ef`. Known limitations and follow-up Runtime V2 later replaced direct debug-log and close-guard calls with lifecycle and diagnostic services, but retained the requirement that caught exceptions remain observable."},{"title":"Consistent electrochemistry batch analysis","url":"history/records/2026/07/LK-20260713-electrochem-batch-consistency.html","kind":"history","section":"history","keywords":"LK-20260713-electrochem-batch-consistency 2026-07-13 46 fix compatible labkit_CIC_app labkit_VTResistance_app Consistent electrochemistry batch analysis","text":"Consistent electrochemistry batch analysis id: LK-20260713-electrochem-batch-consistency date: 2026-07-13 sequence: 46 type: fix compatibility: compatible component: `labkit_CIC_app` | `1.3.7 -> 1.3.8` component: `labkit_VTResistance_app` | `1.3.7 -> 1.3.8` scope: Consistent electrochemistry batch analysis Context CIC and VT Resistance could retain per-file derived values from different control settings, and CIC could sample outside the recorded time range while displaying a delay without units. Decision and rationale Treat analysis controls as one batch contract and recompute every file before display/export so rows cannot silently mix stale and current parameters. Changes Recompute all loaded files when shared controls change and once more before CSV export. Label CIC delay in microseconds, reject out-of-range sampling, and export the area and delay used for each result. Added family regression coverage and audited sibling electrochem apps. User and data impact Batch rows now represent one consistent area, delay, pulse-detection, resistance-window, and voltage-mode configuration. Invalid delay choices fail instead of extrapolating a misleading value. Compatibility and migration CIC CSV adds trailing `Area_cm2` and `Delay_us` columns. Existing columns keep their names and order; VT Resistance exports remain schema-compatible. Validation Electrochem unit and GUI tests cover batch recomputation, display units, out-of-range handling, and export-time refresh. Evidence The guarded calculations and export builders are app-owned. Commit `67ea2286` introduced the consistent batch-analysis and export behavior. Known limitations and follow-up The fix enforces internal batch consistency but does not choose scientifically appropriate area, delay, or resistance windows for the user."},{"title":"Core, neurophysiology, and ECG project validation ownership","url":"history/records/2026/07/LK-20260716-core-neuro-ecg-project-validation.html","kind":"history","section":"history","keywords":"LK-20260716-core-neuro-ecg-project-validation 2026-07-16 121 refactor compatible labkit_FigureStudio_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app remaining public App project schemas App maintenance cost","text":"Core, neurophysiology, and ECG project validation ownership id: LK-20260716-core-neuro-ecg-project-validation date: 2026-07-16 sequence: 121 type: refactor compatibility: compatible component: `labkit_FigureStudio_app` | `0.2.6 -> 0.2.7` component: `labkit_NerveResponseAnalysis_app` | `1.4.4 -> 1.4.5` component: `labkit_ResponseReviewStats_app` | `1.4.4 -> 1.4.5` component: `labkit_RHSPreview_app` | `1.4.4 -> 1.4.5` component: `labkit_ECGPrint_app` | `1.4.4 -> 1.4.5` scope: remaining public App project schemas scope: App maintenance cost Context The remaining public project validators still surrounded their own style, recording-role, metric-window, protocol, ECG, and result rules with repeated canonical bucket and source-record format checks. Decision and rationale Complete the public-App validation ownership split. Runtime owns canonical bucket structs and source-record internals. Each App continues to require its source collection and to enforce its own fields, role/cardinality rules, numeric limits, tables, annotations, and results. Changes Removed 66 net lines of repeated framework structure checks from Figure Studio, the three neurophysiology Apps, and ECG Print. Preserved Nerve Response Analysis's fixed source ID-role pairs and RHS Preview's recording/protocol/filter roles and cardinalities. Added focused project-spec contracts for default acceptance, missing-source rejection, and the retained neurophysiology role rules. User and data impact Valid projects, migrations, signal calculations, previews, and exports are unchanged. Framework-shape failures now have one Runtime owner; domain-schema failures remain attributable to the App that defines them. Compatibility and migration No payload format changed and no migration is required. All supported saved projects continue through their existing centralized `projectSpec.m` migration entry. Validation Focused project-spec tests cover all five defaults and missing-source cases, plus invalid Nerve and RHS source roles. Representative unit and hidden-GUI workflows cover project reconstruction, preview, analysis, and export behavior. Evidence [Figure Studio](../../../../apps/labkit-core/figure-studio/README.md) [Neurophysiology Apps](../../../../apps/neurophysiology/README.md) [ECG Print](../../../../apps/wearable/ecg-print/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Project validator boilerplate is now removed across the public App fleet. Further App simplification must target independently evidenced action, presentation, or cache patterns rather than weakening domain validation."},{"title":"Cross-platform validation exits cleanly after settled plot fitting","url":"history/records/2026/07/LK-20260721-cross-platform-validation-exit.html","kind":"history","section":"history","keywords":"LK-20260721-cross-platform-validation-exit 2026-07-21 151 fix compatible labkit.app App Framework Continuous Integration","text":"Cross-platform validation exits cleanly after settled plot fitting id: LK-20260721-cross-platform-validation-exit date: 2026-07-21 sequence: 151 type: fix compatibility: compatible component: `labkit.app` | `1.2.2 -> 1.2.3` scope: App Framework scope: Continuous Integration Context Windows headless validation completed every test and report but retained a progress heartbeat resource until the GitHub Actions step timed out. Hosted macOS GUI validation also measured equal-scale plot limits before native layout had settled, producing a platform-specific false failure. Decision and rationale Make lifecycle ownership explicit at the test-runner boundary and measure equal-data-unit limits only after MATLAB has applied pending native layout. This keeps CI diagnostics available while ensuring successful validation exits promptly, without changing the App SDK surface or EIS workflow meaning. Changes Explicitly release each progress plugin and its heartbeat timer when a test runner returns, including nested focused runs. Verify focused runs leave no tagged heartbeat timer behind. Settle native layout before equal-data-unit fitting and assert EIS scaling from the post-action axes allocation. User and data impact Users receive the same transient equal-scale EIS view, now calculated against the displayed axes allocation. Projects, source records, results, and exports are unchanged. Compatibility and migration The patch release is compatible with all 1.x App SDK requirements. No project or result migration is required. Validation Focused nested-runner coverage verifies heartbeat cleanup after return. Focused EIS GUI coverage verifies independent fitting and equal-scale limits. GitHub Actions will re-run the complete platform matrices after delivery. Evidence The timed-out Windows job reported all 468 headless tests and `** Finished headless` more than twenty minutes before the action timeout. The macOS GUI artifact consistently identified the pre-layout equal-scale pixel assertion. Known limitations and follow-up The Windows hosted runner remains the final verification environment for process teardown. Manual visual assessment of plot layout remains outside hidden-GUI automation."},{"title":"Curvature consolidates migration and analysis state","url":"history/records/2026/07/LK-20260716-curvature-project-structure.html","kind":"history","section":"history","keywords":"LK-20260716-curvature-project-structure 2026-07-16 97 refactor compatible labkit_CurvatureMeasurement_app Image Measurement App structure","text":"Curvature consolidates migration and analysis state id: LK-20260716-curvature-project-structure date: 2026-07-16 sequence: 97 type: refactor compatibility: compatible component: `labkit_CurvatureMeasurement_app` | `1.4.2 -> 1.4.3` scope: Image Measurement scope: App structure Context Curvature split static metadata across files, exposed four generic lifecycle functions including a filename-encoded migration, and stored five computation tasks/results under `+appState`. Session restoration also read the nested portable source path directly. Decision and rationale Use one project specification with a version-aware migration entry. Runtime V2 calls `Migrate(project,fromVersion)` for each missing version; Curvature keeps only the actual version-1 transformation. Put fit and length task/result shapes beside the analysis functions that consume them. Changes Consolidated product metadata and requirements in `definition.m`. Consolidated project creation, validation, and the v1 source migration in `projectSpec.m`. Moved decoded-image reconstruction to root `createSession.m`. Moved all five generic state helpers to `+analysisRun`. Removed separate metadata and lifecycle files. Replaced direct portable-reference access with the Runtime path accessor. Kept managed anchor editing, scale calibration, curve fitting, length measurement, overlay rendering, and exports unchanged. User and data impact Opening current or version-1 projects, tracing/removing anchors, calibrating scale, fitting curvature, measuring length, and exporting results behave unchanged. Developers now find every durable-version rule in one file and every numerical result/task next to the numerical implementation. Compatibility and migration The current payload stays at version 2. Version-1 `inputs.source` is still moved to `inputs.sources` exactly once. No new payload migration is introduced. Validation Unit tests cover current project/session construction, v1 migration, fit and length numerics, physical/pixel scales, densification, invalid points, result tables, and deterministic task fingerprints. The hidden GUI suite covers image loading, anchor editing guidance, managed interactions, viewport behavior, scale calibration, results, and save/load. Evidence [Curvature Measurement](../../../../apps/image-measurement/curvature/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Other versioned Apps still use filename-per-step migrations and will move to one project entry during their own behavior audits."},{"title":"DIC Postprocess adopts one product and project declaration","url":"history/records/2026/07/LK-20260716-dic-postprocess-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-dic-postprocess-project-spec 2026-07-16 83 refactor compatible labkit_DICPostprocess_app DIC Project lifecycle","text":"DIC Postprocess adopts one product and project declaration id: LK-20260716-dic-postprocess-project-spec date: 2026-07-16 sequence: 83 type: refactor compatibility: compatible component: `labkit_DICPostprocess_app` | `1.4.1 -> 1.4.2` scope: DIC scope: Project lifecycle Context DIC Postprocess split static product metadata across `definition.m`, `requirements.m`, and `version.m`, while its version-1 durable schema occupied three generic `+appLifecycle` files. None of those separations represented a separate scientific capability or independently evolving contract. Decision and rationale Make `definition.m` the product declaration and `projectSpec.m` the only durable-schema entry. Keep `createSession.m` separate because it restores file-backed strain, image, mask, and prepared overlay caches that must not be serialized into the project. Changes Moved command metadata, version, update date, and facade requirements into the definition. Consolidated project defaults and validation behind one project spec. Moved transient reconstruction to one explicitly named package-root entry. Removed the two metadata files and generic lifecycle package. Replaced the stale GUI-free manual example with an executable call matching the real input structure, complete parameter contract, and three outputs. Kept all calculation, parameter, action, presentation, and export behavior unchanged. User and data impact Ncorr loading, overlay preparation, statistics, save/load, and exports behave unchanged. Maintainers can now find the complete product contract in one file and the complete durable schema in one adjacent file. Compatibility and migration The command, project ID, payload version, fields, defaults, validation rules, and source records are unchanged. Existing DIC Postprocess projects require no migration. Validation Unit tests exercise Ncorr loading, cached session reconstruction, numerical preparation, summary/export behavior, and presentation. The hidden GUI flow launches the real App and generates overlays and a summary through Runtime V2. Evidence [DIC Postprocess](../../../../apps/dic/dic-postprocess/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up The action file remains a meaningful workflow boundary because it coordinates input selection, calculation, export, diagnostics, and dialogs. Its naming and possible smaller capability boundaries will be compared across the DIC family instead of changed in isolation."},{"title":"DIC Preprocess consolidates product and project declarations","url":"history/records/2026/07/LK-20260716-dic-preprocess-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-dic-preprocess-project-spec 2026-07-16 84 refactor compatible labkit_DICPreprocess_app DIC Project lifecycle","text":"DIC Preprocess consolidates product and project declarations id: LK-20260716-dic-preprocess-project-spec date: 2026-07-16 sequence: 84 type: refactor compatibility: compatible component: `labkit_DICPreprocess_app` | `1.5.1 -> 1.5.2` scope: DIC scope: Project lifecycle Context DIC Preprocess split static product metadata across three files and split one version-1 durable schema across a generic lifecycle package. That structure made a maintainer traverse six declarations before reaching any registration, crop, or mask behavior. Decision and rationale Make `definition.m` the complete product declaration and `projectSpec.m` the only durable-schema entry. Keep `createSession.m` explicit because decoding source images and replaying alignment/crop steps reconstructs transient cache state rather than defining persistence. Changes Moved command metadata, version, update date, and facade requirements into the definition. Consolidated project defaults and validation behind one project spec. Moved transient image and edit replay to one package-root session factory. Removed the metadata files and generic lifecycle package. Kept registration, crop, mask, history, managed interactions, export, and scientific parameter behavior unchanged. User and data impact Manual and automatic alignment, zoom-preserving point/ROI editing, crop and mask history, project save/load, and exports behave unchanged. The durable and transient state boundaries are now visible from two adjacent files. Compatibility and migration The command, project ID, payload version, fields, defaults, validation, source records, edit steps, and mask history are unchanged. Existing projects require no migration. Validation Unit tests cover project/session reconstruction, state history, registration, crop/mask calculations, source IO, exports, and presenter models. The hidden GUI workflow covers real launch, manual point matching, ROI crop, mask editing, viewport preservation, and generated outputs. Evidence [DIC Preprocess](../../../../apps/dic/dic-preprocess/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up The `+appState` package mixes edit-history and mask-geometry capabilities. It is retained for this compatibility-preserving checkpoint and will be split or renamed by responsibility after its callers and tests are audited."},{"title":"DIC Preprocess replaces its generic state bucket","url":"history/records/2026/07/LK-20260716-dic-preprocess-state-capabilities.html","kind":"history","section":"history","keywords":"LK-20260716-dic-preprocess-state-capabilities 2026-07-16 85 refactor compatible labkit_DICPreprocess_app DIC App ownership","text":"DIC Preprocess replaces its generic state bucket id: LK-20260716-dic-preprocess-state-capabilities date: 2026-07-16 sequence: 85 type: refactor compatibility: compatible component: `labkit_DICPreprocess_app` | `1.5.2 -> 1.5.3` scope: DIC scope: App ownership Context The generic `+appState` package mixed three unrelated concepts: durable align/crop undo history, mask editing and undo, and a predicate over transient source-image cache state. The name exposed storage mechanics without helping a maintainer find the behavior they needed. Decision and rationale Group these operations by the capability that owns their invariants. `editHistory` owns align/crop snapshots and reset behavior, `maskEditing` owns mask canvas composition and undo snapshots, and `sourceFiles` owns the loaded image-pair predicate. None is promoted to LabKit because the project fields, undo limits, image semantics, and operation order are specific to DIC Preprocess. Changes Moved four edit-history operations into `+editHistory`. Moved five mask composition/history operations into `+maskEditing`. Moved the image-pair readiness predicate into `+sourceFiles`. Updated actions, presenters, preview requests, and direct state tests to use the capability paths. Removed the generic `+appState` package without adding an adapter. User and data impact All controls, calculations, undo limits, project fields, masks, alignment/crop history, and viewport behavior are unchanged. Code navigation now starts from the user capability rather than an undifferentiated state bucket. Compatibility and migration This is an app-internal ownership change. Project payloads and public GUI-free scientific APIs are unchanged, so saved projects require no migration. Validation State tests cover history trimming, reset/restore behavior, mask composition, and image-pair readiness through the new capability paths. The full DIC Preprocess unit and hidden GUI workflows verify the unchanged callers. Evidence [DIC Preprocess](../../../../apps/dic/dic-preprocess/README.md) [Architecture](../../../../development/build-apps/architecture.md) Known limitations and follow-up `definitionActions.m` remains a large but cohesive workflow coordinator. Its callbacks will be compared with other interaction-heavy image Apps before any further extraction; file length alone is not a reason to create another technical package."},{"title":"DIC and Gait project validation ownership","url":"history/records/2026/07/LK-20260716-dic-gait-project-validation-ownership.html","kind":"history","section":"history","keywords":"LK-20260716-dic-gait-project-validation-ownership 2026-07-16 120 refactor compatible labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_GaitAnalysis_app DIC and Gait project schemas App maintenance cost","text":"DIC and Gait project validation ownership id: LK-20260716-dic-gait-project-validation-ownership date: 2026-07-16 sequence: 120 type: refactor compatibility: compatible component: `labkit_DICPostprocess_app` | `1.4.4 -> 1.4.5` component: `labkit_DICPreprocess_app` | `1.5.5 -> 1.5.6` component: `labkit_GaitAnalysis_app` | `2.0.5 -> 2.0.6` scope: DIC and Gait project schemas scope: App maintenance cost Context DIC Postprocess, DIC Preprocess, and Gait repeated Runtime's canonical project and source-record shape checks around their real domain constraints. The duplication made it harder to see which saved fields these Apps actually own. Decision and rationale Retain each App's required source collection and domain schema while relying on Runtime for canonical bucket structs and source-record internals. DIC continues to own alignment, crop, mask, summary, and parameter fields; Gait continues to own pose-analysis options, numeric limits, and result structure. Changes Removed 26 net lines of repeated framework structure checks from the three project specifications. Preserved every App-required source field and domain-specific validator. Added GUI-free DIC and Gait contracts that accept default projects and reject projects missing their required source collection. User and data impact Valid DIC and Gait projects, migrations, calculations, and exports are unchanged. Malformed framework structures still fail in Runtime and malformed domain fields still fail in the owning App. Compatibility and migration No payload format changed and no migration is required. Supported older projects continue through the same App-owned migration callbacks. Validation Focused project-spec tests cover default acceptance and missing-source rejection. Hidden GUI workflows cover representative DIC load/edit/analysis and Gait project load/step-analysis behavior. Evidence [DIC Apps](../../../../apps/dic/README.md) [Gait Analysis](../../../../apps/gait/gait-analysis/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up This boundary cleanup does not change the scientific gait analysis or image registration algorithms. Their domain complexity remains App-owned."},{"title":"DIC uses framework-owned optional source slots","url":"history/records/2026/07/LK-20260716-dic-source-slots.html","kind":"history","section":"history","keywords":"LK-20260716-dic-source-slots 2026-07-16 93 refactor compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app DIC Runtime source boundary","text":"DIC uses framework-owned optional source slots id: LK-20260716-dic-source-slots date: 2026-07-16 sequence: 93 type: refactor compatibility: compatible component: `labkit.ui` | `7.4.0 -> 7.4.1` component: `labkit_DICPostprocess_app` | `1.4.2 -> 1.4.3` component: `labkit_DICPreprocess_app` | `1.5.3 -> 1.5.4` scope: DIC scope: Runtime source boundary Context DIC Preprocess and Postprocess use stable semantic source slots such as `referenceImage`, `movingImage`, `maskImage`, and `dicMat`. Those slots are legitimately absent before the user selects a file. Each App therefore carried an identical `pathForId.m` wrapper that returned empty text for an unset slot and otherwise inspected the nested portable reference. The first source accessor required every requested ID to exist. Applying that rule would have preserved the duplicate wrapper instead of lowering App cost. Decision and rationale Make ID-based source lookup preserve the requested shape and return an empty string for a semantic slot that has not been added. Continue to reject malformed records and references. This matches ordinary presenter and session behavior without hiding corrupt project data. Changes Refined `sourcePaths(sources,ids)` for optional semantic slots. Removed both DIC `pathForId.m` wrappers and their duplicate schema knowledge. Migrated DIC loading, summaries, presenters, save defaults, and export paths to the Runtime accessor. Preserved alignment, crop, mask, anchor, rendering, calculation, and export behavior. User and data impact An empty DIC project still presents empty file controls and enables them as the workflow requires. Selected and relinked files load through the same paths. Developers no longer implement a source-ID lookup helper for each App. Compatibility and migration The accessor change relaxes one error case and is compatible within UI 7. No saved project shape changed and no DIC payload migration is required. Validation Runtime unit tests cover mixed present and absent IDs. DIC unit and hidden-GUI tests cover empty startup, file selection, point matching, ROI and mask edits, viewport-preserving interaction, project state, and result export. Evidence [DIC Preprocess](../../../../apps/dic/dic-preprocess/README.md) [DIC Postprocess](../../../../apps/dic/dic-postprocess/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Other families still contain direct portable-reference reads. They will move to the same accessor before the repository-wide no-leak contract is enabled."},{"title":"DTA facade and app ownership boundaries","url":"history/records/2026/05/LK-20260529-dta-facade-and-app-boundaries.html","kind":"history","section":"history","keywords":"LK-20260529-dta-facade-and-app-boundaries 2026-05-29 2 refactor compatible historical project evolution","text":"DTA facade and app ownership boundaries id: LK-20260529-dta-facade-and-app-boundaries date: 2026-05-29 sequence: 2 type: refactor compatibility: compatible scope: historical project evolution Context The first extraction pass separated calculations from the imported GUIs, but the electrochem apps still depended on a broad internal package and shared session helpers. A new app could reuse a parser only by learning implementation details that had nothing to do with reading a DTA file. Decision and rationale Make DTA loading the reusable boundary and keep workflow decisions in the app that owns them. The public layer would load one file, discover files, or load a folder and return documented report structures. Plot labels, callback order, session state, result summaries, and export choices would remain app concerns. This distinction became an early form of LabKit's present architecture: a small library presents stable data operations, while an app owns the laboratory workflow assembled around those operations. Changes Added GUI-independent DTA loading and adopted it in the EIS and Chrono Overlay apps. Added discovery and folder-loading operations, including validation for empty selections, missing folders, and expected experiment kinds. Documented and tested the report schemas returned by batch operations. Moved EIS, Chrono Overlay, CSC, VT Resistance, and CIC out of the original `gamrywb` namespace and into app-owned entry points. Returned calculation details, labels, callback flow, and exports to their owning apps when they were not genuinely reusable. Introduced boundary tests to prevent UI, data, IO, analysis, and utility packages from growing through accidental cross-dependencies. User and data impact Electrochem users kept the same principal workflows, but file-loading failures became more explicit and batch loading gained a defined result report. App authors could use the DTA layer without starting a GUI or depending on the layout of an existing app. No laboratory file format or scientific result schema was intentionally changed by the ownership cleanup. Compatibility and migration The supported app commands replaced direct use of the old `gamrywb` package. Code that reached into that package's internal helpers needed to move either to the DTA facade or into the app that owned the behavior. Validation The period added DTA schema tests, empty- and missing-folder tests, architectural boundary checks, and behavior-focused calculation tests. The repository did not yet have the later unified MATLAB test command, so no single historical validation invocation is available. Evidence GUI-free loading facade `88b19851` and initial app adoption `789ef507`, `0ccc3ad6`. App ownership migration `1ee8e82d` through `1b6042bf`. Discovery and folder loading `c06946d9`, `82f4146d`. Report documentation and contract tests `669eea38`, `e04292c0`. Boundary and failure-handling work from `ad2b6c74` through `7506fa32`. Known limitations and follow-up The public surface was still organized around the first electrochem use cases. The next stage renamed the workbench, narrowed the package map further, and tested whether the same app-first approach could support image and biosignal workflows."},{"title":"Debug sample packs","url":"history/records/2026/07/LK-20260701-debug-sample-packs.html","kind":"history","section":"history","keywords":"LK-20260701-debug-sample-packs 2026-07-01 28 feat compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app Debug sample packs","text":"Debug sample packs id: LK-20260701-debug-sample-packs date: 2026-07-01 sequence: 28 type: feat compatibility: compatible component: `labkit.ui` | `3.3.1 -> 3.4.0` component: `labkit_DICPostprocess_app` | `1.2.4 -> 1.3.0` component: `labkit_DICPreprocess_app` | `1.2.2 -> 1.3.0` component: `labkit_ChronoOverlay_app` | `1.2.1 -> 1.3.0` component: `labkit_CIC_app` | `1.2.1 -> 1.3.0` component: `labkit_CSC_app` | `1.2.1 -> 1.3.0` component: `labkit_EIS_app` | `1.2.1 -> 1.3.0` component: `labkit_VTResistance_app` | `1.2.1 -> 1.3.0` component: `labkit_BatchImageCrop_app` | `1.5.1 -> 1.6.0` component: `labkit_CurvatureMeasurement_app` | `1.2.4 -> 1.3.0` component: `labkit_FLIRThermal_app` | `1.1.2 -> 1.2.0` component: `labkit_FocusStack_app` | `1.3.0 -> 1.4.0` component: `labkit_ImageEnhance_app` | `1.4.1 -> 1.5.0` component: `labkit_ImageMatch_app` | `1.4.1 -> 1.5.0` component: `labkit_NerveResponseAnalysis_app` | `1.2.4 -> 1.3.0` component: `labkit_ResponseReviewStats_app` | `1.2.3 -> 1.3.0` component: `labkit_RHSPreview_app` | `1.2.4 -> 1.3.0` component: `labkit_ECGPrint_app` | `1.2.2 -> 1.3.0` scope: Debug sample packs Context Debug reports could identify a failed callback, but reproducing the failure still depended on the original laboratory file and the user's exact sequence of actions. Those inputs were often unavailable to the person investigating the report and were unsuitable as permanent test fixtures. Decision and rationale Let every app create a small, synthetic sample pack that exercises its normal loading path without containing laboratory data. Store the generated inputs and expected output location beside the debug artifacts so a report can be replayed from one self-contained folder. Changes `labkit.ui` `3.3.1 -> 3.4.0` All supported apps moved into the `1.3.x`, `1.4.x`, `1.5.x`, or `1.6.x` debug-sample-pack lines. Added app-owned debug sample packs. Added debug artifact sample and output folders. User and data impact Debug mode gained a repeatable demonstration dataset for each supported app. These packs were synthetic and intended for diagnosis, not as substitutes for real experiment files or as reference scientific results. Compatibility and migration The sample packs were additive debug assets. Existing app inputs and outputs were unchanged, and no user file was copied into a pack. Validation Commit `279befbc` added coverage tests for every app family, focused tests for DIC, electrochem, image, RHS, and wearable sample writers, and layout checks that exercised the generated packs. Evidence Main commit `279befbc`. Known limitations and follow-up Sample packs were deliberately app-owned because each workflow knows which inputs make a useful reproduction. They do not contain or archive a user's original files."},{"title":"Debug workflows, launcher tools, and changelog governance","url":"history/records/2026/07/LK-20260707-debug-workflows-launcher-tools-and-changelog-governance.html","kind":"history","section":"history","keywords":"LK-20260707-debug-workflows-launcher-tools-and-changelog-governance 2026-07-07 39 feat compatible labkit_launcher labkit_launcher labkit_launcher labkit.ui labkit.ui labkit_DICPreprocess_app labkit_BatchImageCrop_app labkit_FocusStack_app labkit_FigureStudio_app Debug workflows, launcher tools, and changelog governance","text":"Debug workflows, launcher tools, and changelog governance id: LK-20260707-debug-workflows-launcher-tools-and-changelog-governance date: 2026-07-07 sequence: 39 type: feat compatibility: compatible component: `labkit_launcher` | `1.2.4 -> 1.2.5` component: `labkit_launcher` | `1.2.5 -> 1.2.6` component: `labkit_launcher` | `1.2.6 -> 1.2.7` component: `labkit.ui` | `5.0.0 -> 5.0.1` component: `labkit.ui` | `5.0.1 -> 5.0.2` component: `labkit_DICPreprocess_app` | `1.3.4 -> 1.3.5` component: `labkit_BatchImageCrop_app` | `1.6.6 -> 1.6.7` component: `labkit_FocusStack_app` | `1.4.5 -> 1.4.6` component: `labkit_FigureStudio_app` | `0.1.4 -> 0.1.5` scope: Debug workflows, launcher tools, and changelog governance Context The first complete debug sample packs exposed several false failures. A modal file chooser could be mistaken for a stalled callback, DIC could read an older ROI snapshot than the editor displayed, duplicate crops needed confirmation before export, and Focus Stack's folder workflow was hard to reach from its sample instructions. The launcher was also becoming a practical maintenance and distribution tool. Code Analyzer reports needed a durable home outside launcher source, individual apps needed an offline package format, and private app workspaces needed to remain discoverable without entering the public repository. Finally, the growing changelog needed to explain the direction of the project, not merely repeat tags and commit subjects. Decision and rationale Use v3.1.0 as a stabilization release for reproducible debug workflows. Treat native modal dialogs as active UI, read live editor state when it is newer than the stored snapshot, and make required gestures visible in the app. Move code analysis and packaging into dedicated tools, let the launcher invoke them, and keep private app discovery separate from public release contents. Changes Release tag `v3.1.0` `labkit_launcher` `1.2.4 -> 1.2.7` `labkit.ui` `5.0.1 -> 5.0.2` `labkit_FigureStudio_app` `0.1.4 -> 0.1.5` `labkit_DICPreprocess_app` `1.3.4 -> 1.3.5` `labkit_BatchImageCrop_app` `1.6.6 -> 1.6.7` `labkit_FocusStack_app` `1.4.5 -> 1.4.6` DIC Preprocess ROI mask export now reads the live ROI editor anchors when building a mask, so preview/save do not misreport a drawn ROI as empty when editor state is newer than the app state snapshot. DIC Preprocess keeps the double-click ROI anchor workflow and makes the double-click requirement explicit in the visible details text. Batch Image Crop duplicate tasks now redraw with finite preview overlay coordinates while still requiring users to confirm the duplicated crop center before export. Figure Studio quick PNG/JPG/SVG export actions use runtime-compatible handler signatures. Focus Stack exposes a direct `Choose folder` action for loading all supported images from a focus-stack folder. Debug trace diagnostics no longer write stalled-callback crash reports while a file chooser modal is active. Moved the launcher Code Analyzer scan into `tools/codecheck`, which writes timestamped JSON/HTML report pairs under `artifacts/code-check/` without overwriting earlier runs. Added launcher actions and a deployment tool that package one selected LabKit app into a standalone zip, either as source `.m` files or encoded `.p` files. Added launcher discovery for local private app workspaces under `private_apps/apps/` and roots named by `LABKIT_PRIVATE_APP_ROOTS`. Clarified the public changelog model as a project evolution map organized by reader-facing evolution entries, with release tags and commits kept as anchors and evidence rather than the primary structure. User and data impact The supplied debug packs could be followed without producing a false crash report or an apparently disabled workflow. DIC mask export used the anchors currently visible in the editor, duplicate crops remained blocked until their centers were confirmed, and Focus Stack offered a direct folder action. Maintainers gained timestamped HTML and JSON Code Analyzer reports. A selected app could be packaged for production or offline use without tests, unrelated apps, or repository metadata. Private apps could live beside the checkout, appear in the ordinary launcher, and retain their own repository and history. Compatibility and migration DIC ROI editing still uses double-click to add anchors; no interaction-mode migration is required. Existing file-panel image selection remains available in Focus Stack. Code Analyzer report consumers should read the timestamped `artifacts/code-check/matlab_code_issues_*.json` files. Full LabKit checkout installs are unchanged. Single-app packages can start through either the packaged launcher or the direct run file; P-code packages require MATLAB to run the generated `.p` files. Public apps, public releases, and public CI remain scoped to `apps/`. Validation PR #34 updated debug sample, ROI, crop, folder-loading, launcher-tool, deployment, and private-workspace tests before its squash merge. Tag `v3.1.0` points to release commit `9db01952`; the exact local command sequence was not recorded in this page. Evidence PR #34 squash merge `9db01952` and release tag `v3.1.0`. Known limitations and follow-up The first deployment tool packaged one app at a time. Multi-app bundles were added later. The changelog model introduced here was subsequently replaced by component-linked history pages generated with the documentation site."},{"title":"Declarative app runtime","url":"history/records/2026/07/LK-20260703-declarative-app-runtime.html","kind":"history","section":"history","keywords":"LK-20260703-declarative-app-runtime 2026-07-03 32 refactor compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app Declarative app runtime","text":"Declarative app runtime id: LK-20260703-declarative-app-runtime date: 2026-07-03 sequence: 32 type: refactor compatibility: compatible component: `labkit.ui` | `3.4.4 -> 3.4.5` component: `labkit_DICPostprocess_app` | `1.3.0 -> 1.3.1` component: `labkit_DICPreprocess_app` | `1.3.0 -> 1.3.1` component: `labkit_ChronoOverlay_app` | `1.3.0 -> 1.3.1` component: `labkit_CIC_app` | `1.3.0 -> 1.3.1` component: `labkit_CSC_app` | `1.3.0 -> 1.3.1` component: `labkit_EIS_app` | `1.3.0 -> 1.3.1` component: `labkit_VTResistance_app` | `1.3.0 -> 1.3.1` component: `labkit_BatchImageCrop_app` | `1.6.1 -> 1.6.2` component: `labkit_CurvatureMeasurement_app` | `1.3.0 -> 1.3.1` component: `labkit_FLIRThermal_app` | `1.2.0 -> 1.2.1` component: `labkit_FocusStack_app` | `1.4.0 -> 1.4.1` component: `labkit_ImageEnhance_app` | `1.5.0 -> 1.5.1` component: `labkit_ImageMatch_app` | `1.5.0 -> 1.5.1` component: `labkit_NerveResponseAnalysis_app` | `1.3.0 -> 1.3.1` component: `labkit_ResponseReviewStats_app` | `1.3.0 -> 1.3.1` component: `labkit_RHSPreview_app` | `1.3.0 -> 1.3.1` component: `labkit_ECGPrint_app` | `1.3.1 -> 1.3.2` scope: Declarative app runtime Context Apps had adopted common shells and controls, but each runner still assembled callbacks, startup steps, refresh behavior, and debug hooks in its own order. Understanding an app meant reading a long construction procedure before reaching the scientific workflow. Decision and rationale Describe an app through a definition containing its layout, actions, state, startup, and rendering contracts, then let the runtime perform the common wiring. Keep action bodies, calculations, and result structures in the app so the definition exposes workflow structure without becoming a generic analysis language. Changes `labkit.ui` `3.4.4 -> 3.4.5` All supported apps received patch bumps. Migrated apps to declarative workflow runtime. User and data impact The visible workflows were intended to remain the same. For maintainers, each app gained a recognizable definition and lifecycle, while repeated setup moved out of its runner. Debug sample packs and focused app tests continued to call the same app-owned operations. Compatibility and migration Users kept the same app entry points and data files. App implementations moved to definitions and runtime actions; unsupported code that reached into old runner construction details needed to adopt the declarative APIs. Validation The migration changed 545 files and updated the affected app, layout, export, calculation, sample-pack, and package-boundary suites in the same commit. The commit message records final profiler and debug evidence; the exact local command was not preserved in this history. Evidence Main commit `568b3e9b`. Known limitations and follow-up The first declarative vocabulary still used the mixed `app`, `spec`, `view`, `tool`, and `diag` package names. The UI 4 and UI 5 passes refined how groups, plots, interactions, and lifecycle responsibilities were named."},{"title":"Default LabKit close protection","url":"history/records/2026/07/LK-20260709-default-labkit-close-protection.html","kind":"history","section":"history","keywords":"LK-20260709-default-labkit-close-protection 2026-07-09 43 fix compatible labkit.ui labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app Default LabKit close protection","text":"Default LabKit close protection id: LK-20260709-default-labkit-close-protection date: 2026-07-09 sequence: 43 type: fix compatibility: compatible component: `labkit.ui` | `5.0.2 -> 5.0.3` component: `labkit_FocusStack_app` | `1.4.6 -> 1.4.7` component: `labkit_ImageEnhance_app` | `1.5.5 -> 1.5.6` component: `labkit_ImageMatch_app` | `1.5.5 -> 1.5.6` scope: Default LabKit close protection Context Only apps that installed a dirty-state guard warned before closing. A newly created public or private app could therefore discard work silently until its author implemented and tested a separate guard. Repeated close shortcuts could also race with a modal confirmation. Decision and rationale Make close confirmation a default property of every framework-owned app window and remove the optional app-facing guard API. Keep one in-window prompt active at a time; a repeated close shortcut confirms that prompt instead of opening another one. Changes `labkit.ui` `5.0.2 -> 5.0.3` `labkit_FocusStack_app` `1.4.6 -> 1.4.7` `labkit_ImageEnhance_app` `1.5.5 -> 1.5.6` `labkit_ImageMatch_app` `1.5.5 -> 1.5.6` LabKit runtime figures now show an in-window confirmation prompt before any framework-owned app window closes, even when the app has not marked itself dirty. Removed the app-facing `labkit.ui.runtime.setCloseGuard` API and migrated existing app close-guard dirty checks to the framework default behavior. Repeating or holding the app close shortcut while the in-window prompt is active confirms the close. User and data impact Every public or private LabKit app asked before its window closed, even if the app had no custom dirty-state logic. Users gained a consistent protection against accidental closure at the cost of one confirmation step. Compatibility and migration Closing LabKit apps now requires one confirmation step by default. App code that calls `labkit.ui.runtime.setCloseGuard` must remove that call; close confirmation is framework-owned. Validation Commit `0c9f472b` expanded the UI busy-state GUI suite for initial close, cancel, confirmation, and repeated-shortcut behavior, then updated public- surface and app-compatibility checks. Evidence Mainline commit `0c9f472b`. Known limitations and follow-up This policy protected the window, not the semantic completeness of each saved project. Runtime V2 later combined default close handling with app-owned dirty state and lifecycle services."},{"title":"Destination-rebased source references","url":"history/records/2026/07/LK-20260716-destination-rebased-source-references.html","kind":"history","section":"history","keywords":"LK-20260716-destination-rebased-source-references 2026-07-16 74 fix compatible labkit.ui project serialization named save, explicit autosave, and recovery","text":"Destination-rebased source references id: LK-20260716-destination-rebased-source-references date: 2026-07-16 sequence: 74 type: fix compatibility: compatible component: `labkit.ui` | `6.0.4 -> 6.0.5` scope: project serialization scope: named save, explicit autosave, and recovery Context Runtime source records were created before an App knew its future project-file location, so they began with an empty `relativePath`. Project-envelope creation copied those records unchanged. As a result, the resolver supported relative references, but ordinary Runtime V2 saves did not actually generate them. Decision and rationale Rebase source references at the serialization boundary using the actual MAT destination. A named project, app-owned autosave, and framework recovery file can live in different folders, so each write must calculate its own relative path rather than reusing a path cached in live state. Changes Passed the real destination path into every Runtime V2 envelope writer. Copied the durable project and refreshed reference schema, relative path, original path, and filename immediately before serialization. Preserved additive app/reference fields while replacing standard path fields. Kept resolved absolute paths in live state so current-session readers do not need to interpret portable references. User and data impact A project and its source directory can now move together to another root or machine and reopen through the saved relative relationship even when the old absolute path no longer exists. Existing projects without a relative path remain readable through their original-path and relink fallbacks. Compatibility and migration The envelope and source-reference schema versions are unchanged. No payload migration is needed: the next named save, explicit autosave, or recovery write adds the destination-correct relative path. Validation The Runtime V2 project GUI test saves a source/project directory tree, verifies the generated relative path, moves the tree, and reloads from the new root. Video Marker verifies that its source-adjacent explicit autosave is rebased from the autosave destination. Existing atomic-save, relink, recovery, and additive field tests remain in the same focused suites. Evidence [Runtime and Data Model](../../../../framework/guides/runtime.md) explains when relative paths are created and how they are resolved. [UI Framework](../../../../framework/README.md) describes Runtime V2 project ownership and persistence. Known limitations and follow-up The portable-reference creation and resolution algorithms remain public in UI 6 for compatibility. They are implementation mechanics rather than App-facing workflow APIs and are reviewed with the remaining Runtime public surface for a single future major-boundary cleanup."},{"title":"Documentation navigation follows topic hierarchy","url":"history/records/2026/07/LK-20260717-hierarchical-documentation-navigation.html","kind":"history","section":"history","keywords":"LK-20260717-hierarchical-documentation-navigation 2026-07-17 132 docs compatible MATLAB documentation site navigation","text":"Documentation navigation follows topic hierarchy id: LK-20260717-hierarchical-documentation-navigation date: 2026-07-17 sequence: 132 type: docs compatibility: compatible scope: MATLAB documentation site navigation Context The documentation site exposed its major areas in the top bar, but each area's left sidebar was a flat list. Related app families, development tasks, and API packages were not visually distinguished, so readers could not readily see the path from an area to a topic and then to a specific page. Decision and rationale Render contextual hierarchy from the existing page and catalog metadata. App families, libraries, development tasks, and MATLAB packages become labeled sidebar branches. This preserves one structured source of navigation truth while making downstream topics visible from their area landing pages. Changes Grouped app navigation by family and indented app manuals below family pages. Grouped function, framework, and development navigation by topic. Grouped API siblings under their owning MATLAB package. Defined the second `nav` entry in `docs/site.json` as the branch label and ordered branches by their earliest page. Added responsive sidebar styling and renderer regression coverage for the hierarchy. User and data impact Readers can move from a top-level area to a topic branch and then to a specific manual without searching a flat list. Documentation content, URLs, MATLAB behavior, and scientific data are unchanged. Compatibility and migration Existing page URLs and top-level navigation remain compatible. Documentation authors should assign new multi-page topics a stable second-level `nav` label in `docs/site.json`. Validation The documentation renderer regression verifies Development topic groups, App family branches, and API package labels. `docsCheck` rebuilds and compares the complete generated site. Evidence The generated area landing pages contain labeled branch headings and parent/child link classes derived from tracked page and app catalog metadata. Known limitations and follow-up Single-page areas do not display an artificial empty branch. History records remain in the generated timeline because reproducing the full record set in the sidebar would make navigation less usable."},{"title":"Documentation rendering avoids repeated model capture","url":"history/records/2026/07/LK-20260717-documentation-render-performance.html","kind":"history","section":"history","keywords":"LK-20260717-documentation-render-performance 2026-07-17 130 perf compatible MATLAB documentation renderer","text":"Documentation rendering avoids repeated model capture id: LK-20260717-documentation-render-performance date: 2026-07-17 sequence: 130 type: perf compatibility: compatible scope: MATLAB documentation renderer Context Two project documentation tests each rebuild the complete tracked site. Profiling showed that most render time was not file generation or tree comparison: every inline Markdown fragment created an anonymous function that captured the complete documentation model before scanning links. Decision and rationale Pass the shared model and current page directly into token protection and dispatch code, image, and link rendering by token type. This preserves the renderer contract and generated bytes while avoiding thousands of large closure allocations. Changes Replaced per-fragment renderer closures with direct token dispatch. Retained the same code, image, link, emphasis, and nested inline-code behavior. Added a focused regression guard against restoring the measured closure pattern. User and data impact Generated HTML is byte-for-byte unchanged. Documentation rebuilds, consistency checks, and the launcher documentation action complete substantially sooner. Compatibility and migration `renderLabKitDocs`, `checkLabKitDocs`, `buildtool docs`, and `buildtool docsCheck` retain their existing syntax, outputs, and failure behavior. No migration is required. Validation On the same MATLAB R2025a host and complete `checkLabKitDocs` scenario, profiler total time decreased from 46.52 seconds to 9.66 seconds, approximately 79 percent. The after-profile run also completed the byte comparison against the tracked site. Evidence The focused renderer regression protects inline link behavior and the allocation fix. `docsCheck` independently rebuilds all narrative and API pages and compares every generated file. Known limitations and follow-up Absolute times vary by machine and filesystem. API help rendering is now the largest measured renderer-owned cost and should be changed only after a separate profile identifies a safe optimization."},{"title":"Documentation search ranks page intent and scopes history explicitly","url":"history/records/2026/07/LK-20260720-ranked-and-scoped-documentation-search.html","kind":"history","section":"history","keywords":"LK-20260720-ranked-and-scoped-documentation-search 2026-07-20 146 docs compatible Documentation system tools/docs/ site search","text":"Documentation search ranks page intent and scopes history explicitly id: LK-20260720-ranked-and-scoped-documentation-search date: 2026-07-20 sequence: 146 type: docs compatibility: compatible scope: Documentation system scope: tools/docs/ scope: site search Context The generated documentation search treated every term in a page title, body, and rendered component-history links as equivalent. A shared history record could therefore make an unrelated App page appear before the App named by a search. Readers also had no way to restrict a query to history records. Decision and rationale Keep component-history links visible on their related pages, but index history records as their own searchable documents. Give title and explicit keywords more weight than body text, then provide a visible section filter for readers who want Apps, APIs, history, or another documentation area. Changes Added section and keyword fields to generated search entries. Excluded rendered component-history link text from narrative page search bodies while retaining complete history-record search entries. Added deterministic field-weighted ranking, result excerpts, and section filtering to the offline-safe client search. Added regression coverage for search-entry separation, filters, and ranking contracts. User and data impact Searching a named App now favors that App and its family over unrelated pages that share a historical record. Readers can search only History when tracing a decision. No App behavior, calculations, projects, exports, or laboratory data changes. Compatibility and migration The generated site remains usable from file:// without network fetches. Existing documentation URLs, history records, and page-level change-history links remain unchanged. Validation Focused documentation search contract tests verify the generated index and client controls. Documentation rendering and consistency checks regenerate the tracked site and validate the history record. Evidence renderLabKitDocs now emits separated search fields. The client script ranks title, keyword, and body matches independently and filters by the generated section field. Known limitations and follow-up Search is intentionally dependency-free and uses exact lexical matching. Typo-tolerant suggestions can be considered later only if they preserve the current deterministic title-first ordering."},{"title":"Documentation structure becomes the navigation contract","url":"history/records/2026/07/LK-20260719-path-derived-documentation.html","kind":"history","section":"history","keywords":"LK-20260719-path-derived-documentation 2026-07-19 136 refactor compatible labkit_launcher Documentation renderer Documentation maintenance","text":"Documentation structure becomes the navigation contract id: LK-20260719-path-derived-documentation date: 2026-07-19 sequence: 136 type: refactor compatibility: compatible component: `labkit_launcher` | `1.5.1 -> 1.5.2` scope: Documentation renderer scope: Documentation maintenance Context The local HTML site duplicated documentation ownership across Markdown files, `site.json`, two catalog JSON files, and generated output. Moving or adding a page therefore required several coordinated edits. Markdown links also embedded many relative paths without a repository-owned way to repair links after a move. Decision and rationale Treat the `docs/` directory structure as the narrative navigation contract. Discover public Apps from `labkit_launcher(\"list\")`, associate each App with its unique path-conventional manual, and discover public API pages from complete MATLAB help contracts. Keep ordinary relative Markdown links so source pages remain useful in GitHub and add a checker that can repair a broken link only when its destination is unambiguous. The generated `site/` remains the offline and local HTML product. It is still produced exclusively by the repository renderer. Changes Removed `docs/site.json` and the App and API catalog JSON files. Reorganized development and framework guides into path-owned navigation groups and moved the API landing page to `docs/reference/README.md`. Made the renderer discover Markdown pages, public Apps, and complete public MATLAB help without duplicated registries. Added `maintainLabKitDocLinks` for checking and uniquely repairing relative Markdown links after file moves. Changed launcher documentation lookup to derive the selected App manual and generated HTML path from App discovery and documentation structure. Removed obsolete compatibility redirect pages instead of preserving legacy documentation routes. User and data impact Local HTML documentation and launcher documentation actions remain available. Contributors add or move a page by placing Markdown in the intended directory and running the link maintainer and renderer; no navigation catalog needs a matching edit. Scientific behavior and project data are unchanged. Compatibility and migration Existing current documentation links are rewritten to their new relative paths. Old generated documentation routes are intentionally retired and are not maintained as redirect pages. Rebuild `site/` after updating a checkout. Validation Focused documentation contract and renderer regression tests cover discovery, navigation, link repair, public API help, and launcher documentation lookup. The documentation checker validates the generated site after a clean local render. Evidence [Documentation Build Tools](../../../../development/tools/documentation.md) [Maintaining LabKit Documentation](../../../../development/maintain-and-release/documentation.md) [LabKit Launcher](../../../../apps/labkit-core/launcher/README.md) [API Reference](../../../../reference/README.md) Known limitations and follow-up Automatic link repair deliberately refuses ambiguous destinations. Authors must resolve those cases explicitly so the checker never guesses between pages with the same filename or title."},{"title":"Durable Video Marker source metadata","url":"history/records/2026/07/LK-20260716-video-marker-durable-metadata.html","kind":"history","section":"history","keywords":"LK-20260716-video-marker-durable-metadata 2026-07-16 70 feat compatible labkit_VideoMarker_app project payload schema downstream gait inputs","text":"Durable Video Marker source metadata id: LK-20260716-video-marker-durable-metadata date: 2026-07-16 sequence: 70 type: feat compatibility: compatible component: `labkit_VideoMarker_app` | `1.4.1 -> 1.5.0` scope: project payload schema scope: downstream gait inputs Context Video Marker previously kept frame rate, frame count, duration, and image size only in transient decoded-video state. Its MAT project preserved coordinates but a GUI-independent downstream analysis could not recover time semantics without reopening the original video or inventing a frame rate. Decision and rationale Make immutable decoded-video facts part of the durable Video Marker project. The portable source record continues to own the file path; the metadata record contains only finite numeric facts required to interpret saved annotations. Changes Advanced the Video Marker project payload from version 1 to version 2. Added durable frame count, frame rate, duration, height, and width. Populate metadata when a video or marker CSV is opened and seed rebuilt sessions from saved metadata before optional source decoding. Refresh durable metadata from the reopened source before an explicit **Save autosave**, so a loaded version 1 autosave upgrades in place. Validate metadata values and annotation/frame-count consistency. Added an ordered v1-to-v2 migration that recovers frame count from saved annotation coordinates and leaves unknowable source facts at zero. User and data impact New named projects and source-adjacent autosaves contain enough timing and geometry information for Gait Analysis to treat the MAT document as its authoritative input. Paths are not duplicated into the metadata record. Compatibility and migration Version 1 LabKit project envelopes remain readable. Opening one marks it for an upgrade; saving writes payload version 2. A frame rate absent from version 1 cannot be inferred from coordinates alone and remains zero until the source is opened by the current Video Marker app. Validation Video Marker unit tests verify metadata selection, absence of transient paths, frame-count recovery, payload validation, and mismatched annotation rejection. The existing GUI suite covers video opening, marker CSV import, project saves, and recovery loading. Evidence [Video Marker](../../../../apps/image-measurement/video-marker/README.md) documents the persisted fields and downstream use. Gait Analysis input tests exercise the current payload contract separately. Known limitations and follow-up Projects whose old payload never recorded a frame rate must reopen their source video before producing a fully self-describing current project. Opening that source through the saved reference and pressing **Save autosave** performs the upgrade without another location prompt."},{"title":"ECG Print uses one project contract","url":"history/records/2026/07/LK-20260716-ecg-print-structure.html","kind":"history","section":"history","keywords":"LK-20260716-ecg-print-structure 2026-07-16 106 refactor compatible labkit_ECGPrint_app Wearable App structure","text":"ECG Print uses one project contract id: LK-20260716-ecg-print-structure date: 2026-07-16 sequence: 106 type: refactor compatibility: compatible component: `labkit_ECGPrint_app` | `1.4.2 -> 1.4.3` scope: Wearable scope: App structure Context ECG Print kept product metadata in separate requirement and version functions, and split one durable schema across project creation, validation, migration, and session reconstruction files under a generic lifecycle package. Session and presentation code also read the Runtime-owned portable-reference structure directly. Decision and rationale Use the compact Runtime V2 App structure. The definition owns product metadata and optional capabilities, one project contract owns durable schema evolution, and one root session factory rebuilds decoded signal state. ECG-specific parsing, analysis, presentation, and result packages already express real workflow capabilities and remain App-owned. Changes Consolidated command identity, display metadata, version, requirements, layout, actions, presenter, renderer, and debug capability in `definition`. Concentrated project creation, validation, and the version-1 source upgrade in `projectSpec` behind one `Migrate` callback. Moved transient recording and analysis reconstruction to root `createSession` and reused that factory when clearing a failed decode. Replaced nested portable-reference reads with semantic `sourcePaths` lookup. Removed the generic lifecycle package and separate requirement/version files. Updated the App package structure guardrail so actions, presentation, project persistence, and transient sessions are optional capabilities; Apps that adopt root `projectSpec` cannot regress to split lifecycle metadata. User and data impact Recording import, parsing controls, channel selection, filtering, peak detection, segmentation, template construction, SNR measurements, plots, exports, manifests, project reopening, and user wording are unchanged. The App version advances to 1.4.3; durable payload version remains 2. Compatibility and migration Version-1 projects still move their singular source record into the canonical source collection before validation. Runtime V2 now invokes the single migration entry and owns iteration to the current payload version. Current version-2 project files require no data transformation. Validation Focused GUI-free tests cover the migration callback, definition contract, import parsing, analysis products, presentation models, and result tables. The hidden GUI workflow covers launch, recording import, analysis, plots, both exports, project save, and session reconstruction after load. Project guardrails cover the compact optional-capability structure, embedded metadata, version/history ownership, and generated documentation consistency. Evidence [ECG Print](../../../../apps/wearable/ecg-print/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Development](../../../../development/build-apps/app-development.md) Known limitations and follow-up Automated tests do not judge ECG morphology, peak quality, or the visual suitability of exported waveforms for a particular experiment. Remaining Runtime V2 App migrations and the stale agent guidance require separate review."},{"title":"EIS consolidates its product and project contracts","url":"history/records/2026/07/LK-20260716-eis-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-eis-project-spec 2026-07-16 89 refactor compatible labkit_EIS_app Electrochemistry Project lifecycle","text":"EIS consolidates its product and project contracts id: LK-20260716-eis-project-spec date: 2026-07-16 sequence: 89 type: refactor compatibility: compatible component: `labkit_EIS_app` | `1.4.1 -> 1.4.2` scope: Electrochemistry scope: Project lifecycle Context EIS split static product metadata across three files and one first-version project schema across a generic lifecycle package. Those files did not own separate impedance or plotting contracts. Decision and rationale Make `definition.m` the complete product declaration and `projectSpec.m` the sole durable-schema entry. Keep `createSession.m` explicit because restoring decoded ZCURVE items and source selection is genuine transient work. Changes Consolidated command metadata, version, update date, and requirements in the definition. Consolidated project defaults and validation behind one project spec. Moved decoded curve and selection restoration to a package-root session factory. Removed separate metadata files and the generic lifecycle package. Delayed log-scale assignment until filtered positive data establishes valid automatic limits, and corrected the GUI regression fixture to use a legal positive manual range while testing stale-zoom replacement. Kept impedance values, Nyquist/Bode axis semantics, log scaling, zoom behavior, and export schemas unchanged. User and data impact Launch, multi-file selection, plotting, zoom, save/load, and export behavior remain unchanged. Project and transient state ownership are now adjacent and explicit. Compatibility and migration The project remains version 1 with identical fields, defaults, validation, and source records. Existing EIS projects require no migration. Validation Unit tests cover ZCURVE parsing, axis values, Nyquist mode, log scaling, project/session contracts, presentation, and export columns. The hidden GUI workflow covers real launch, file loading, plot interaction, save/load, and export. Evidence [EIS](../../../../apps/electrochemistry/eis/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Source restoration still consumes portable-reference internals. The planned shared source-path service will remove that leak across all Apps together."},{"title":"EIS delegates source identity reconciliation to Runtime V2","url":"history/records/2026/07/LK-20260716-eis-runtime-source-reconciliation.html","kind":"history","section":"history","keywords":"LK-20260716-eis-runtime-source-reconciliation 2026-07-16 110 refactor compatible labkit_EIS_app Electrochemistry App structure Runtime adoption","text":"EIS delegates source identity reconciliation to Runtime V2 id: LK-20260716-eis-runtime-source-reconciliation date: 2026-07-16 sequence: 110 type: refactor compatibility: compatible component: `labkit_EIS_app` | `1.4.3 -> 1.4.4` scope: Electrochemistry scope: App structure scope: Runtime adoption Context EIS already stored only portable source records in its durable project, but its action file still generated source IDs, appended records, and removed records with App-local helpers. That duplicated Runtime V2's source reconciliation service and made the App responsible for an identity invariant owned by project persistence. The EIS session factory also repeated empty workflow and view buckets even though Runtime V2 canonicalizes missing transient buckets. Decision and rationale Use `services.project.reconcileSources` as the single source-record owner after successful file additions, removals, and clearing. The EIS workflow continues to decide which decoded files are accepted and their order; Runtime preserves matching source identities and allocates collision-free identities for new files. Return only EIS-specific selection and decoded-cache state from `createSession`. Runtime supplies the empty workflow and view buckets before the state becomes visible to actions or presenters. Changes Removed EIS-local source-ID generation, append, and removal helpers. Reconciled durable source records from the successfully decoded EIS items. Removed empty workflow and view boilerplate from the session factory. Added GUI assertions for canonical Runtime buckets, unique source IDs, and identity preservation across additions and project reopen. Advanced the EIS App version to 1.4.4. User and data impact File selection, decoding, plotting, export, save, and reopen behavior are unchanged. Existing saved source IDs remain stable when their paths match. Newly added records receive Runtime-managed IDs. IDs are persistence identities and are not displayed as scientific results. Compatibility and migration The project payload remains version 1 and needs no migration. Existing project files continue to load through their stored portable references. Validation The EIS hidden GUI workflow covers two-file loading from separate folders, selection, plotting, export, project save, clear, and reopen. Focused unit and contract tests cover EIS calculations, App structure, version ownership, documentation, and history ordering. Evidence [EIS](../../../../apps/electrochemistry/eis/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Development](../../../../development/build-apps/app-development.md) Known limitations and follow-up Other multi-file Apps still contain equivalent local source-list helpers. They should adopt the same Runtime service only after their role and ordering semantics are verified by their own focused tests."},{"title":"EIS uses explicit plot-view actions","url":"history/records/2026/07/LK-20260721-eis-explicit-plot-views.html","kind":"history","section":"history","keywords":"LK-20260721-eis-explicit-plot-views 2026-07-21 147 fix compatible labkit_EIS_app EIS Overlay","text":"EIS uses explicit plot-view actions id: LK-20260721-eis-explicit-plot-views date: 2026-07-21 sequence: 147 type: fix compatibility: compatible component: `labkit_EIS_app` | `1.5.1 -> 1.5.2` scope: EIS Overlay Context EIS inferred an equal X/Y aspect ratio from specific Nyquist axis selections. That implicit choice could shrink the usable plotting area and make a redraw look unlike the user's current view. Decision and rationale Keep plot semantics in EIS, but use the App framework's viewport revision and data-fitting capability for view behavior. Equal data units are now an explicit one-time view reset rather than a rule tied to axis labels or a constraint on later zooming. Changes Removed the EIS axis-label rule that automatically selected `axis equal`. Added **Fit X/Y limits** for independent data-fitted limits. Added **Use equal X/Y scale** for an explicit equal-data-unit view without changing the plot size allocated by the App layout. Kept ordinary zoom and wheel viewports under the framework-managed viewport preservation path. User and data impact Nyquist plots now begin with independent limits and a stable plot area. Equal scaling preserves the App layout's plot size. The new view buttons change only transient presentation; EIS sources, projects, calculations, and exports are unchanged. Compatibility and migration Existing saved projects remain valid. The selected axes and Log X/Y options keep their existing meaning; the equal-aspect choice is intentionally not saved with the project. Validation The EIS GUI workflow test covers both buttons, independent fitting, explicit equal aspect, and preservation of an ordinary manually chosen viewport. Evidence The renderer now uses `labkit.app.plot.fitAxesToGraphics` for both independent fits and equal-data-unit limits, and receives a new view revision only from an explicit view action. Known limitations and follow-up Automated GUI coverage cannot assess visual balance on every monitor and MATLAB release. Verify the Nyquist layout interactively before a release. labkit.app.plot.fitAxesToGraphics Fit axes limits to finite plotted X/Y data."},{"title":"Electrochem Apps stop reading portable references","url":"history/records/2026/07/LK-20260716-electrochem-source-boundary.html","kind":"history","section":"history","keywords":"LK-20260716-electrochem-source-boundary 2026-07-16 92 refactor compatible labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app Electrochemistry Runtime source boundary","text":"Electrochem Apps stop reading portable references id: LK-20260716-electrochem-source-boundary date: 2026-07-16 sequence: 92 type: refactor compatibility: compatible component: `labkit_ChronoOverlay_app` | `1.4.2 -> 1.4.3` component: `labkit_CIC_app` | `1.4.2 -> 1.4.3` component: `labkit_CSC_app` | `1.4.2 -> 1.4.3` component: `labkit_EIS_app` | `1.4.2 -> 1.4.3` component: `labkit_VTResistance_app` | `1.4.2 -> 1.4.3` scope: Electrochemistry scope: Runtime source boundary Context The Electrochem Apps already delegated portable source creation, save-time rebasing, and load-time relinking to Runtime V2. Their session factories, source loaders, actions, and presenters nevertheless read the runtime's nested path field directly. CIC and VT Resistance also carried duplicate local path extraction functions. Decision and rationale Use the public Runtime source-path accessor at every App boundary. This keeps lazy-loading and batch-selection policies App-owned while removing knowledge of the portable-reference storage schema. Changes Replaced direct nested-reference reads in all five Electrochem Apps. Removed duplicate CIC and VT Resistance path extraction functions. Preserved source order and lazy first-item decoding. Kept DTA parsing, formulas, thresholds, plots, exports, and error wording unchanged. User and data impact File selection, project reopen/relink, calculation, preview, and export behavior are unchanged. App code now expresses only its workflow use of paths; Runtime V2 owns how those paths are stored and resolved. Compatibility and migration No project schema or saved source record changed. Existing projects require no migration and remain compatible with the same UI 7 contract range. Validation The Electrochem unit and hidden-GUI suites cover project reconstruction, DTA loading, selection, plotting, computation, export, and saved-state workflows. Package and version guardrails verify the shared API and component metadata. Evidence [Electrochemistry Apps](../../../../apps/electrochemistry/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Other App families still contain direct reads and will migrate in their own behavior-tested commits before a repository-wide no-leak guard is enabled."},{"title":"Electrochemistry source-field validation boundary","url":"history/records/2026/07/LK-20260716-electrochem-source-field-validation.html","kind":"history","section":"history","keywords":"LK-20260716-electrochem-source-field-validation 2026-07-16 118 fix compatible labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app electrochemistry project schemas malformed project rejection","text":"Electrochemistry source-field validation boundary id: LK-20260716-electrochem-source-field-validation date: 2026-07-16 sequence: 118 type: fix compatibility: compatible component: `labkit_ChronoOverlay_app` | `1.4.5 -> 1.4.6` component: `labkit_CIC_app` | `1.4.5 -> 1.4.6` component: `labkit_CSC_app` | `1.4.5 -> 1.4.6` component: `labkit_EIS_app` | `1.4.5 -> 1.4.6` component: `labkit_VTResistance_app` | `1.4.5 -> 1.4.6` scope: electrochemistry project schemas scope: malformed project rejection Context Runtime owns the format of a portable source record but intentionally allows a project whose `inputs` bucket has no `sources` field. Static and embedded-data Apps may not use external sources. The first electrochemistry validator reduction correctly removed record-format duplication but also stopped declaring that these five file-backed Apps require a source collection. Decision and rationale Keep field presence with the App schema and record shape with Runtime. This is the narrow ownership split: the App decides whether sources are required; Runtime decides what every supplied source record means. Changes Restored the `inputs.sources` presence requirement in all five electrochemistry project validators. Added a GUI-free unit contract that accepts each default project and rejects the same project after its App-required source collection is removed. Kept canonical bucket and source-record field validation out of the Apps. User and data impact Valid projects are unchanged. A malformed electrochemistry project missing its entire source collection is rejected by the App validator before session reconstruction instead of failing later while decoded data are rebuilt. Compatibility and migration No saved format changed and no migration is required. Every project created or saved by these Apps already contains `inputs.sources`. Validation The focused project-spec test covers all five accepted defaults and all five missing-source rejection cases. The Runtime project and electrochemistry GUI tests continue to cover canonical record validation and working file flows. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) separates framework-owned record shape from App-owned fields and roles. The [Electrochemistry App manuals](../../../../apps/electrochemistry/README.md) identify the required App source collection. Known limitations and follow-up The same distinction must be applied explicitly while reducing validators in other App families; a generic source format does not imply that every App has the same required source fields or roles."},{"title":"Explicit application autosave","url":"history/records/2026/07/LK-20260716-explicit-autosave.html","kind":"history","section":"history","keywords":"LK-20260716-explicit-autosave 2026-07-16 68 feat compatible labkit.ui labkit_VideoMarker_app Runtime V2 project recovery Video Marker session workflow","text":"Explicit application autosave id: LK-20260716-explicit-autosave date: 2026-07-16 sequence: 68 type: feat compatibility: compatible component: `labkit.ui` | `6.0.2 -> 6.0.3` component: `labkit_VideoMarker_app` | `1.3.0 -> 1.4.0` scope: Runtime V2 project recovery scope: Video Marker session workflow Context Runtime V2 already wrote debounced recovery generations after durable edits, but an app could only expose the named-project save operation. Video Marker users who wanted to force the current recovery point had no direct control and using **Save State** introduced a destination prompt for an unnamed project. Decision and rationale Expose the existing framework-owned recovery writer as an injected action service. The service accepts the current action state, writes the same bounded recovery generations as the timer, and deliberately leaves the named project path and dirty status unchanged. Video Marker exposes that operation as **Save autosave** in its Session panel. Changes Factored the atomic recovery-generation writer out of the timer scheduler. Added `services.project.saveAutosave(state)` for an immediate, pathless recovery write. Added the Video Marker **Save autosave** button and visible workflow log acknowledgement. Kept ordinary **Save State** as the separate operation for choosing or updating a named project file. User and data impact Clicking **Save autosave** does not open a native file dialog. It updates the current app/document recovery file and retains one previous generation. It does not make the recovery file the active named project and does not suppress later unsaved-close protection. Compatibility and migration Existing projects, recovery files, and automatic autosave behavior remain compatible. Apps that do not expose the new service behave exactly as before. Validation The focused Video Marker GUI workflow verifies that the button immediately creates a recovery file while the runtime document path remains empty. The existing Runtime V2 project test continues to cover debouncing, bounded generations, and recovery loading. Evidence [Runtime and lifecycle](../../../../framework/guides/runtime.md) documents the injected recovery operation and its distinction from named saves. [Video Marker](../../../../apps/image-measurement/video-marker/README.md) documents the Session button and no-dialog behavior. Known limitations and follow-up An autosave is a recovery aid, not a user-named archival project. Users still use **Save State** when they need a deliberate project filename or location."},{"title":"Explicit layout action contract","url":"history/records/2026/07/LK-20260717-explicit-layout-action-contract.html","kind":"history","section":"history","keywords":"LK-20260717-explicit-layout-action-contract 2026-07-17 123 refactor compatible labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_GaitAnalysis_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_VideoMarker_app labkit_FigureStudio_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app Runtime V2 layout callback resolution public App maintenance cost","text":"Explicit layout action contract id: LK-20260717-explicit-layout-action-contract date: 2026-07-17 sequence: 123 type: refactor compatibility: compatible component: `labkit_DICPostprocess_app` | `1.4.5 -> 1.4.6` component: `labkit_DICPreprocess_app` | `1.5.6 -> 1.5.7` component: `labkit_ChronoOverlay_app` | `1.4.6 -> 1.4.7` component: `labkit_CIC_app` | `1.4.6 -> 1.4.7` component: `labkit_CSC_app` | `1.4.6 -> 1.4.7` component: `labkit_EIS_app` | `1.4.6 -> 1.4.7` component: `labkit_VTResistance_app` | `1.4.6 -> 1.4.7` component: `labkit_GaitAnalysis_app` | `2.0.6 -> 2.0.7` component: `labkit_BatchImageCrop_app` | `1.7.5 -> 1.7.6` component: `labkit_CurvatureMeasurement_app` | `1.4.5 -> 1.4.6` component: `labkit_FLIRThermal_app` | `1.4.5 -> 1.4.6` component: `labkit_FocusStack_app` | `1.5.4 -> 1.5.5` component: `labkit_ImageEnhance_app` | `1.6.5 -> 1.6.6` component: `labkit_ImageMatch_app` | `1.6.5 -> 1.6.6` component: `labkit_VideoMarker_app` | `1.5.5 -> 1.5.6` component: `labkit_FigureStudio_app` | `0.2.7 -> 0.2.8` component: `labkit_NerveResponseAnalysis_app` | `1.4.5 -> 1.4.6` component: `labkit_ResponseReviewStats_app` | `1.4.5 -> 1.4.6` component: `labkit_RHSPreview_app` | `1.4.5 -> 1.4.6` component: `labkit_ECGPrint_app` | `1.4.5 -> 1.4.6` scope: Runtime V2 layout callback resolution scope: public App maintenance cost Context Every public App layout carried the same local `callbackValue` helper. The helper returned an empty value when a callback field was absent, so a misspelled or unregistered action could survive startup as a control that silently did nothing. Twenty copies also obscured that Runtime already creates the complete callback table from each App definition. Decision and rationale Layouts reference Runtime-generated callbacks directly. MATLAB field access therefore validates the action ID while the data-only layout is built. Runtime remains the single callback-adapter owner; Apps own only their semantic action registries and layout references. Changes Removed the duplicated callback fallback from all 20 public App layouts. Replaced static lookups with direct `callbacks.actionId` references and kept dynamic field access only in three small controls whose action names are supplied by the surrounding layout. Added a fleet-wide contract that creates every App definition and layout with the Runtime callback inventory. Updated direct neurophysiology layout tests to supply explicit callbacks derived from their action registries. User and data impact Correctly registered controls behave as before. A broken App definition now fails during layout construction instead of presenting an inert control. No scientific calculation, project payload, saved file, or interaction semantics changed. Compatibility and migration No project migration is required. This is an App-development contract tightening: custom layouts must register every referenced semantic action. Validation The focused fleet contract builds every public App layout and catches missing or misspelled callback fields. The App package guardrail rejects reintroduced silent callback fallbacks, and focused workflow-layout tests cover direct construction outside a running figure. Evidence [Runtime layout and action rules](../../../../framework/guides/runtime.md#layout-and-action-rules) [Apps](../../../../apps/README.md) [App development](../../../../development/build-apps/app-development.md) Known limitations and follow-up This change deliberately does not merge short semantic actions or dynamic control helpers merely to reduce line count. Those remain candidates only when a repeated behavior has one stable, domain-neutral owner."},{"title":"FLIR Thermal separates durable annotations from decoded sources","url":"history/records/2026/07/LK-20260716-flir-thermal-structure.html","kind":"history","section":"history","keywords":"LK-20260716-flir-thermal-structure 2026-07-16 98 refactor compatible labkit_FLIRThermal_app Image Measurement App structure","text":"FLIR Thermal separates durable annotations from decoded sources id: LK-20260716-flir-thermal-structure date: 2026-07-16 sequence: 98 type: refactor compatibility: compatible component: `labkit_FLIRThermal_app` | `1.4.2 -> 1.4.3` scope: Image Measurement scope: App structure Context FLIR Thermal split static metadata across files, spread a version-1 project over a generic lifecycle package, grouped decoded records, durable annotations, and numerical reading updates under `+appState`, and read nested portable reference fields in session, actions, and presentation. Its startup callback also selected an output directory before the user loaded a source. Decision and rationale Use the compact Runtime V2 contract while preserving the boundary between decoded radiometric data and the lightweight annotations safe to persist. Assign each remaining helper to the capability it describes instead of moving thermal semantics into the framework. Changes Consolidated product metadata, version, requirements, and optional capabilities in `definition.m`. Consolidated durable project creation and validation in `projectSpec.m` and moved selected-image reconstruction to root `createSession.m`. Moved decoded item shape to `+sourceFiles`, point/ROI updates to `+analysisRun`, and persistent per-image readings to `+thermalAnnotations`. Removed separate metadata files, generic lifecycle/state packages, and the redundant App startup callback. Replaced all direct portable-reference field access with the Runtime source path accessor. User and data impact Radiometric decoding, Celsius conversion, range controls, point and ROI readings, viewport-preserving overlays, project reopen, and exports keep their existing behavior. Empty launch no longer chooses an output folder; adding sources still establishes the same source-adjacent default. Developers can find transient decoded matrices, scientific readings, and durable annotations under their actual owners without learning a generic state layer. Compatibility and migration The durable payload remains version 1 with identical fields and defaults. Existing projects require no migration. The removed App-specific debug line is replaced by the Runtime's standard debug-startup message. Validation Five unit methods cover radiometric import, thermal values, calibration diagnostics, range controls, independent ROIs, rendering mappings, manifests, and exported matrices. Two hidden GUI workflows cover multi-file selection, session caching, managed region interaction, project save/load reconstruction, shared ranges, and batch export. Evidence [FLIR Thermal](../../../../apps/image-measurement/flir-thermal/README.md) [Thermal Library](../../../../libraries/thermal/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Other Image Measurement Apps still use generic lifecycle/state packages and will be reviewed individually. Automated GUI tests do not replace manual judgment of pointer feel, visual calibration, or camera-specific accuracy."},{"title":"FLIR display tuning","url":"history/records/2026/07/LK-20260703-flir-display-tuning.html","kind":"history","section":"history","keywords":"LK-20260703-flir-display-tuning 2026-07-03 36 feat compatible labkit_CSC_app labkit_FLIRThermal_app labkit_FLIRThermal_app labkit_FLIRThermal_app FLIR display tuning","text":"FLIR display tuning id: LK-20260703-flir-display-tuning date: 2026-07-03 sequence: 36 type: feat compatibility: compatible component: `labkit_CSC_app` | `1.3.6 -> 1.3.7` component: `labkit_FLIRThermal_app` | `1.2.4 -> 1.2.5` component: `labkit_FLIRThermal_app` | `1.2.5 -> 1.2.6` component: `labkit_FLIRThermal_app` | `1.2.6 -> 1.2.7` scope: FLIR display tuning Context The initial FLIR renderer used a fixed color transfer. Images with a narrow or skewed temperature distribution could therefore hide useful contrast even when the numeric range was correct. CSC voltage/current CSV output also needed clearer cycle organization for direct downstream use. Decision and rationale Separate the displayed color mapping from the temperature values. Apply gamma only while rendering the normalized image and expose it as a user control; keep the temperature matrix, point readings, ROI means, and exports numerically unchanged. Refine CSC CSV structure at its result writer rather than in the UI. Changes `labkit_FLIRThermal_app` `1.2.4 -> 1.2.7` `labkit_CSC_app` `1.3.6 -> 1.3.7` Refined CSC CV export. Added FLIR gamma color mapping and made gamma adjustable. User and data impact FLIR users could reveal contrast in hotter or cooler parts of an image without changing the underlying temperatures. The same gamma was used in displayed and exported color renderings. CSC users received a more directly usable voltage/current table. Compatibility and migration Existing FLIR inputs remained valid, and gamma affected rendered color only. Temperature matrices and measurement values did not require conversion. Validation The commits extended CSC export assertions, FLIR rendering and output tests, and the FLIR layout test for the gamma control. Exact historical commands were not recorded. Evidence Main commits `ee5b8f79`, `65dbf5ae`, and `f076561e`. Known limitations and follow-up Gamma changes visual contrast only. Quantitative interpretation must use the temperature values and scale, not colors sampled from the rendered image."},{"title":"Facade contract baseline and release validation hardening","url":"history/records/2026/06/LK-20260623-facade-contract-baseline-and-release-validation-hardening.html","kind":"history","section":"history","keywords":"LK-20260623-facade-contract-baseline-and-release-validation-hardening 2026-06-23 11 ci compatible labkit.biosignal labkit.dta labkit.rhs labkit.ui labkit.ui labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_CurvatureMeasurement_app Facade contract baseline and release validation hardening","text":"Facade contract baseline and release validation hardening id: LK-20260623-facade-contract-baseline-and-release-validation-hardening date: 2026-06-23 sequence: 11 type: ci compatibility: compatible component: `labkit.biosignal` | `new -> 1.0.0` component: `labkit.dta` | `new -> 1.0.0` component: `labkit.rhs` | `new -> 1.0.0` component: `labkit.ui` | `new -> 2.0.0` component: `labkit.ui` | `2.0.0 -> 2.1.0` component: `labkit.ui` | `2.2.0 -> 2.2.1` component: `labkit_DICPostprocess_app` | `1.0.0 -> 1.0.1` component: `labkit_DICPreprocess_app` | `1.0.0 -> 1.0.1` component: `labkit_CurvatureMeasurement_app` | `1.0.0 -> 1.0.1` scope: Facade contract baseline and release validation hardening Context Reusable packages exposed public MATLAB functions, but apps had no machine-checkable way to state which API versions they required. Release and CI checks also needed one consistent build-task entry path. Decision and rationale Give each reusable package version metadata and let apps declare compatible ranges that are checked at launch and in tests. Route MATLAB CI shards through the same build tasks used by maintainers so release validation exercises the documented commands. Changes `labkit.biosignal` `1.0.0` `labkit.dta` `1.0.0` `labkit.rhs` `1.0.0` `labkit.ui` `2.0.0 -> 2.2.1` DIC Pre/Post and Curvature `1.0.0 -> 1.0.1` Release tags `v2.4.1` and `v2.4.2` Added facade contract metadata and requirement checks. Hardened app lifecycle and release validation contracts. Routed MATLAB CI shards through build tasks. User and data impact An incompatible app/package combination could fail with a direct requirement message instead of producing a later missing-function error. Existing project and result data were unaffected. Compatibility and migration The contract metadata described the existing public facades and was additive for app callers. Apps with an incompatible declared requirement now failed at launch with a version diagnostic instead of continuing unpredictably. Validation The listed commits introduced contract, lifecycle, and CI build-task tests. Release tags `v2.4.1` and `v2.4.2` identify the shipped checkpoints; exact local commands were not recorded. Evidence Main commits `a25b79f9`, `3673e548`, `49d9f41b`, and `7e39b558`. Known limitations and follow-up App and launcher display versions were added in the separate version-metadata change later the same day."},{"title":"Figure Studio adopts one product definition","url":"history/records/2026/07/LK-20260716-figure-studio-single-definition.html","kind":"history","section":"history","keywords":"LK-20260716-figure-studio-single-definition 2026-07-16 79 refactor compatible labkit_FigureStudio_app labkit.ui LabKit Core App structure","text":"Figure Studio adopts one product definition id: LK-20260716-figure-studio-single-definition date: 2026-07-16 sequence: 79 type: refactor compatibility: compatible component: `labkit_FigureStudio_app` | `0.2.1 -> 0.2.2` component: `labkit.ui` | `7.2.0 -> 7.2.1` scope: LabKit Core scope: App structure Context Figure Studio declared its command, names, family, App version, and LabKit requirement in two files separate from the runtime definition. Its entrypoint joined all three factories even though they described one product. Decision and rationale Use Figure Studio as the first reviewed App migration to the single-definition contract. This validates the reduced structure on an App that also accepts a typed axes handoff, without changing its plotting or export behavior. Changes Moved exact product metadata and the UI requirement into `definition.m`. Reduced the public entrypoint to one definition plus its existing typed request adapter. Removed the redundant `requirements.m` and `version.m` files. Taught the version guard to use `AppVersion` in a migrated definition while comparing the first migration against the previous `version.m` baseline. Fixed the shared source reconciler so it creates the canonical empty source array without first constructing an invalid empty-ID placeholder record. Added `services.results.emptyOutputs()` and used it for Figure Studio's variable-length export manifest instead of constructing an invalid empty-ID placeholder output. User and data impact Launch, axes handoff, style controls, project payload, FIG reading, plot snapshot extraction, and all export formats retain their existing behavior. Maintainers now update one product contract instead of three files. Compatibility and migration The App command and project ID are unchanged. App version metadata requests still return the same fields through the public entrypoint. Existing project payloads remain at version 1 and require no data migration. Validation Focused tests cover ordinary launch, axes handoff, style changes, project round-trip, exports, launcher discovery, requirements/version requests, and version/history governance. Evidence [Figure Studio](../../../../apps/labkit-core/figure-studio/README.md) documents the unchanged workflow and new definition ownership. [Runtime and Lifecycle](../../../../framework/guides/runtime.md) defines the shared product contract. Known limitations and follow-up Figure Studio still has a meaningful version-1 project schema, rebuildable plot session cache, and startup resource installation. These will move to the projectSpec/action capability model after the framework supports that model; they were not deleted merely to reduce file count."},{"title":"Figure Studio consolidates its project schema","url":"history/records/2026/07/LK-20260716-figure-studio-project-spec.html","kind":"history","section":"history","keywords":"LK-20260716-figure-studio-project-spec 2026-07-16 82 refactor compatible labkit_FigureStudio_app LabKit Core Project lifecycle","text":"Figure Studio consolidates its project schema id: LK-20260716-figure-studio-project-spec date: 2026-07-16 sequence: 82 type: refactor compatibility: compatible component: `labkit_FigureStudio_app` | `0.2.2 -> 0.2.3` scope: LabKit Core scope: Project lifecycle Context Figure Studio's version-1 project creation and validation lived in separate files under a generic `+appLifecycle` package. The package name described a framework phase rather than the durable capability those functions owned. Decision and rationale Consolidate the complete durable schema behind `projectSpec.m`. Keep `createSession.m` separate at the App package root because it performs a different job: rebuilding transient selection and decoded plot cache from a validated project. Changes Added one project declaration with local create and validate functions. Moved session reconstruction to one explicitly named package-root entry. Removed the three-file generic `+appLifecycle` package. Left meaningful startup, action, presentation, source, style, and export capabilities unchanged. User and data impact Figure loading, axes handoff, styling, project save/load, session restoration, and exports behave unchanged. A maintainer can now understand the entire durable schema in one file. Compatibility and migration The App command, project ID, payload version, fields, validation, and source record format are unchanged. Existing Figure Studio projects need no migration. Validation The existing unit and hidden GUI suites cover FIG reading, source style, project round-trip, axes handoff, canvas resizing, quick export, and data package export through the consolidated project declaration. Evidence [Figure Studio](../../../../apps/labkit-core/figure-studio/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up The startup hook still owns axes handoff and resize-resource installation. It will be evaluated with other App startup hooks before any shared mount/action capability is introduced."},{"title":"Figure Studio derives its publication preset from the nine-panel reference","url":"history/records/2026/07/LK-20260721-figure-studio-nine-panel-calibration.html","kind":"history","section":"history","keywords":"LK-20260721-figure-studio-nine-panel-calibration 2026-07-21 155 fix compatible labkit_FigureStudio_app LabKit Core","text":"Figure Studio derives its publication preset from the nine-panel reference id: LK-20260721-figure-studio-nine-panel-calibration date: 2026-07-21 sequence: 155 type: fix compatibility: compatible component: `labkit_FigureStudio_app` | `0.6.1 -> 0.6.4` scope: LabKit Core Context The previous Figure Studio publication profile was described as a visual calibration even though its dimensions had been taken from a separate manual FIG example. It also allowed native figure chrome to reduce the exported drawable height. Decision and rationale Use only the maintained 3-by-3 scientific reference. Normalize every panel by its detected axes frame, measure typography and strokes in pixels, and select one robust profile from all nine panels. Keep those measurements app-local and size the chromeless export client area directly so the configured inner frame survives raster and vector export. Changes Recalibrated the reference plot frame, typography, semantic strokes, frame, grid, legend border, and legend token length from panels A through I. Set the data stroke to 6.5 pt after registered raster checks matched panel A exactly and reduced the remaining one-pixel deficits in panels E and H. Removed menu and toolbar chrome from temporary export figures and preserved the complete figure bounds through `exportgraphics`. Ignored zero-area text extents when computing outer margins so native log rulers cannot inflate an export canvas to tens of thousands of pixels. Added the calibrated 900 px plot width to the selectable sizes and made it the new-project default. Retained source token geometry for **FIG default** while applying the measured long token only to the LabKit preset. Replaced dynamic-array analyzer suppressions with bounded collection and documented the 72-to-96-PPI range used by cross-platform visual metrics. User and data impact New LabKit-style projects open at the nine-panel reference scale. Existing scientific values, limits, source graphics, FIG files, and saved projects are not recalculated. Exports retain the requested inner-frame aspect instead of losing native-window height. Compatibility and migration The style record remains extensible and existing projects stay readable. Switching an existing document to **LabKit figure** opts into the new profile; **FIG default** continues to use source presentation values. Validation Pixel-frame, OCR glyph-height, colored-stroke, and registered-overlay checks against all nine reference panels. Focused Figure Studio result-file and project tests. Hidden-GUI Figure Studio workflow tests. Native logarithmic-axis margin regression. Linux-compatible visual-ratio and analyzer-policy regressions. Repository `changedFast` validation. Evidence After width registration, the nine detected inner-frame height errors range from -1.71 to +2.16 pixels; panel A is exact. Shared OCR glyph heights have a median scale error below one percent. Reference and generated comparison rasters remain untracked validation artifacts. Known limitations and follow-up Raster antialiasing varies slightly by renderer and platform. Exact scientific curve coordinates are source data and are not part of the style preset."},{"title":"Figure Studio edits one native subplot panel at a time","url":"history/records/2026/07/LK-20260721-figure-studio-native-panel-editing.html","kind":"history","section":"history","keywords":"LK-20260721-figure-studio-native-panel-editing 2026-07-21 153 feat compatible labkit_FigureStudio_app Figure Studio","text":"Figure Studio edits one native subplot panel at a time id: LK-20260721-figure-studio-native-panel-editing date: 2026-07-21 sequence: 153 type: feat compatibility: compatible component: `labkit_FigureStudio_app` | `0.4.0 -> 0.6.0` scope: Figure Studio Context Figure Studio reconstructed a limited portable snapshot from the first axes in a FIG. This could omit composite graphics such as traditional `boxplot` groups, gave no reliable way to choose a subplot from a mixed figure, and made export canvas controls look like live plot-resize controls. Decision and rationale Treat an opened FIG as a transient native document resource and select one axes from it by an ordered subplot panel choice. The selected axes remains the authoritative hierarchy for preview and editable/image export; the portable snapshot remains an explicit secondary data-package representation. This gives ordinary MATLAB charts a broader preservation path without promising that an arbitrary custom graphics class is portable. Use a fixed, visually calibrated single-panel default (1600 by 1333, 6:5). The workbench now displays a raster rendering of that real export canvas, fit as one image into the available workspace. Resizing the window never feeds back into style sizing; supersampling remains export-only. Provide an explicit automatic X/Y-limit recovery action instead of trying to infer limits during unrelated style changes. Changes Added ordered mixed-FIG subplot-panel selection; preview, styling, limits, and exports all operate on the selected axes only. Added private native-source cloning for popout handoff and FIG import, with cleanup through the existing document-resource lifecycle. Preserved native child hierarchies in preview and editable FIG export, including traditional grouped `boxplot` graphics and hidden-handle visual children. Preserved source tick labels and tick configuration when copying native axes. Replaced free-form preview resizing with source/fixed export-size choices, aspect choices, export supersampling, and a stable true-export preview. Added **Recalculate X/Y limits** and project persistence for explicit limit overrides. Migrated project schema 3 to remember the selected panel index. User and data impact Existing projects migrate automatically. A saved mixed FIG project restores the same selected panel when its source is available. Popout projects retain a portable snapshot after reload; their private native source is never saved. No scientific calculation, source file, or source axes is modified. Compatibility and migration Schema 1--3 projects migrate to schema 4. Schema 3 adds `panelIndex = 1`; earlier migrations retain their existing style and limit conversions. Validation Project-schema tests cover migrations through schema 4. Hidden-GUI tests cover four-panel FIG selection, native boxplot preservation for FIG import and popout handoff, export, limit recovery, and a stable export-canvas preview through workspace resizing. Focused visual review checks a generated single-panel scientific probe at the default 1600-by-1333 reference size. Evidence The focused test artifacts and generated local visual probe are supporting evidence. No external laboratory data was used. Known limitations and follow-up Developer-led visual review remains necessary for unusual custom charts, native dialogs, and publication-specific annotation overlap. Portable data packages intentionally support fewer object types than native FIG export."},{"title":"Figure Studio fixes publication-frame preview and axis controls","url":"history/records/2026/07/LK-20260721-figure-studio-plot-frame-preview.html","kind":"history","section":"history","keywords":"LK-20260721-figure-studio-plot-frame-preview 2026-07-21 154 fix compatible labkit_FigureStudio_app LabKit Core","text":"Figure Studio fixes publication-frame preview and axis controls id: LK-20260721-figure-studio-plot-frame-preview date: 2026-07-21 sequence: 154 type: fix compatibility: compatible component: `labkit_FigureStudio_app` | `0.6.0 -> 0.6.1` scope: LabKit Core Context Figure Studio had treated a requested output size as a whole figure canvas. That made labels and titles consume the configured plot area, and resizing the preview could make the displayed typography unrelated to the eventual export. Copied UIAxes also needed a portable reconstruction path for reliable export. Decision and rationale Treat the requested width and aspect as the inner axes frame. Keep all publication-style calibration within Figure Studio, then calculate an outer figure from the live rendered text extents so visual styling cannot reduce the configured data area. Changes Defined the plot width and aspect controls as the inner axes frame; export now calculates an outer figure around that fixed frame from visible labels, ticks, titles, legends, and annotations. Calibrated the LabKit publication preset from the maintained single-panel visual measurements, including category-specific typography and strokes. Kept the preview as an interactive axes, reflowing its display scale when its allocated area changes without changing saved/export settings. Added explicit X/Y minimum and maximum controls, plus visible-data recalculation with a finite-data envelope expanded by 50 percent. Rebuilt UIAxes sources through the portable renderer for conventional export, retaining displayed scientific axis exponents. User and data impact Existing Figure Studio projects remain compatible. Existing style sizes retain their meaning as a plot frame; the enclosing export figure may grow to avoid clipping external text. No scientific calculations or source figure data are changed. Compatibility and migration The project schema migrates existing style records without changing their stored data. UIAxes exports use the portable display snapshot only for the screen-specific aspect geometry that cannot be transferred to normal axes. Validation Focused Figure Studio result-file and source-axes tests. Hidden-GUI Figure Studio layout tests, including UIAxes export and preview reflow behavior. Pixel-scale visual metrics for the calibrated single-panel output. Evidence The calibrated profile fixes the inner frame at 1237 by 942 pixels. Its generated output reports that same axes size while the enclosing figure grows only for required outer text and annotations. Known limitations and follow-up Manual review remains appropriate for native MATLAB graphics that cannot be represented by the portable package."},{"title":"Figure Studio names its post-layout initialization capability","url":"history/records/2026/07/LK-20260716-figure-studio-initializer.html","kind":"history","section":"history","keywords":"LK-20260716-figure-studio-initializer 2026-07-16 109 refactor compatible labkit_FigureStudio_app LabKit Core App structure","text":"Figure Studio names its post-layout initialization capability id: LK-20260716-figure-studio-initializer date: 2026-07-16 sequence: 109 type: refactor compatibility: compatible component: `labkit_FigureStudio_app` | `0.2.4 -> 0.2.5` scope: LabKit Core scope: App structure Context Figure Studio was the only public App with a generic `startup.m` file. Its definition already declared the function through Runtime V2's optional `Start` capability, but the filename obscured who invoked it and made the function look like an independent lifecycle entrypoint. Decision and rationale Keep the Runtime-owned `Start` hook because Figure Studio genuinely needs a post-layout phase: it consumes an optional axes handoff, resolves the managed preview axes, and registers a cleanup-owned resize resource. Rename the App callback to `initializeWorkbench` so its capability and invocation boundary are explicit. Do not move GUI/service work into the GUI-free session factory or reintroduce App-owned timers and readiness state. Changes Renamed the Start callback from generic `startup` to `initializeWorkbench` and declared the new handle in `definition`. Documented the callback timing and the request, preview, resource, dialog, workflow, and debug services supplied by Runtime V2. Tightened the App structure guardrail so compact Apps cannot add a generic `startup.m` file outside their declared capability vocabulary. Advanced the Figure Studio App version to 0.2.5. User and data impact Normal launch, default output folder selection, popout axes handoff, source style adoption, preview canvas resize behavior, debug logging, project data, and exports are unchanged. No project migration is required. Compatibility and migration The public command and Runtime definition contract are unchanged. `startup` was an App-internal callback referenced only by the definition; callers should launch the App rather than invoke either callback directly. Validation The Figure Studio hidden GUI suite covers ordinary launch, style controls, FIG loading, preview resize, quick/package export, axes handoff, project save/load, stable canvas sizing, and popout-to-Studio transfer. It also asserts that the definition exposes the semantic initializer handle. Evidence [Figure Studio](../../../../apps/labkit-core/figure-studio/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Development](../../../../development/build-apps/app-development.md) Known limitations and follow-up The Start capability remains necessary for post-layout resources; removing it would require a different framework service phase rather than a file move. App and agent guidance still need a repository-wide terminology audit."},{"title":"Figure Studio preserves common graphics and styles semantic categories","url":"history/records/2026/07/LK-20260720-figure-studio-semantic-restyling.html","kind":"history","section":"history","keywords":"LK-20260720-figure-studio-semantic-restyling 2026-07-20 145 feat compatible labkit_FigureStudio_app labkit.app Figure Studio App Framework GUI validation Test runner","text":"Figure Studio preserves common graphics and styles semantic categories id: LK-20260720-figure-studio-semantic-restyling date: 2026-07-20 sequence: 145 type: feat compatibility: compatible component: `labkit_FigureStudio_app` | `0.3.1 -> 0.4.0` component: `labkit.app` | `1.2.0 -> 1.2.1` scope: Figure Studio scope: App Framework GUI validation scope: Test runner Context Figures sent from Apps, reopened from FIG files, or recreated from Figure Studio data packages could omit common composite graphics such as bars, error bars, areas, and rectangles. Legends were reconstructed only from display names, and the preset exposed one broad line-width control. This made restyling incomplete and could enlarge unrelated text enough to overlap data. Separately, the official hidden-GUI policy was applied while native App windows were constructed but the final show operation could make direct-entrypoint tests visible. Decision and rationale Preserve the supported visible plot structure before applying a presentation preset. Style text and strokes by semantic role so users can establish a coherent baseline and then refine categories that have different visual weights. A preset may style an existing legend, but it retains source placement by default because moving or creating a legend can cover data. Keep GUI-test visibility in the private native adapter. App authors and test methods should not maintain a second hiding convention, and no new public API is needed for a framework-owned launch consistency rule. Keep broad tests in one MATLAB process. A complete local comparison showed that three workers increased both wall-clock and CPU time, so portability work around child-process orchestration would preserve cost without user benefit. Changes Added bar, error-bar, area, and display-only rectangle extraction and reconstruction for previews, FIG imports, and portable recreation scripts. Preserved constant-line labels without interpreting scientific text as a MATLAB line specification. Preserved existing legend text, visibility, placement, orientation, columns, font, interpreter, and border through every supported reconstruction path. Preserved explicit axis ticks, tick labels, rotations, locations, and tick geometry instead of asking MATLAB to infer them again during reconstruction. Included visible hidden-handle graphics in snapshots while retaining their exclusion from automatic legend discovery. Made the LabKit preset the initial style for direct plot handoff while retaining the captured source style as **FIG default**. Added separate controls for title, axis-label, tick, annotation, legend, data, uncertainty, graphic-boundary, reference, and axes styling, plus source/horizontal/45-degree X tick labels. Calibrated the LabKit preset against a representative standard Figure: a 720-by-600 reference canvas, 24/20/15 pt semantic text tiers, 1.1/1.2 pt semantic strokes, Helvetica when available, boxed axes and legend, and a 600 dpi export at the default scale. Scaled text and strokes dynamically from each style's reference canvas while compensating for preview fitting, and reduced UI steps to 0.5 pt for fonts, 0.1 pt for strokes, and 10 px for canvas dimensions. Migrated schema 1 projects to the expanded semantic style model while preserving every previously saved style value. Made the final native show operation honor hidden and minimized GUI validation modes. Bound heartbeat work at timer creation so path-isolation contracts cannot remove a method needed by an active progress callback. Removed internal worker planning, partitioning, process launch, shard selectors, and speculative JUnit shard estimates. Local and CI broad tasks now share the same single-process runner. User and data impact Existing schema 1 documents migrate automatically to schema 2, keeping saved values and supplying defaults only for newly introduced style categories. Supported figures retain more visible content, while unsupported MATLAB chart classes continue to produce explicit warnings. Normal App launches remain visible; only official hidden or minimized validation modes change final window presentation. Compatibility and migration No additional migration applies beyond the compatibility information in the preceding impact section. Validation Result-file tests exercise extraction, FIG reopening, recreation-script execution, legend metadata, constant-line labels, semantic styling, and idempotent preset application. Figure Studio source-axis and hidden-GUI suites cover source defaults, LabKit handoff defaults, the new control surface, preview stability, and popout handoff. Project tests cover schema 1 style migration. Framework GUI coverage verifies that the final show operation retains hidden mode, and a direct DIC Preprocess entrypoint test exercises the full launch path. A same-machine cold-process comparison measured 470 seconds wall time and 876 seconds CPU time for the serial headless gate versus 490 seconds wall time and 1,215 seconds CPU time for three workers. Worker artifacts also confirmed that heartbeat updates survived the isolated-path contract. Evidence The validation details above are the supporting evidence for this record. Known limitations and follow-up Developer-led visual review remains responsible for aesthetic judgment, unusual third-party chart classes, native window behavior, and plot-specific overlap after manual legend placement."},{"title":"Figure Studio preserves overlays above source images","url":"history/records/2026/07/LK-20260722-figure-studio-image-overlay-stacking.html","kind":"history","section":"history","keywords":"LK-20260722-figure-studio-image-overlay-stacking 2026-07-22 156 fix compatible labkit_FigureStudio_app LabKit Core","text":"Figure Studio preserves overlays above source images id: LK-20260722-figure-studio-image-overlay-stacking date: 2026-07-22 sequence: 156 type: fix compatibility: compatible component: `labkit_FigureStudio_app` | `0.6.4 -> 0.6.5` scope: LabKit Core Context Figure Studio copied every visible child from native MATLAB axes, but reversed the source child vector before copying it into the interactive preview. Because MATLAB stores axes children from front to back and `copyobj` preserves vector order, an opaque image became the frontmost child and hid line, marker, and text overlays that had been drawn above it. Decision and rationale Pass the native axes child order through unchanged. The source axes remains the authority for stacking, and Figure Studio must not infer a new order from graphics classes or special-case images. Changes Preserved native front-to-back child order when copying an axes into the interactive preview. Added a synthetic image, line, and text stack regression at the renderer boundary. Added a hidden-GUI regression covering both FIG-file import and axes handoff. User and data impact Image-backed plots now show their visible overlays in Figure Studio and in preview-derived exports. Source files, scientific values, coordinates, object styles, and project data are unchanged. Compatibility and migration No project migration is required. Existing projects receive the corrected stacking when their native source is rebuilt. Validation Exact source-axes stacking regression. Hidden-GUI FIG import and axes-handoff stacking regression. Visual inspection of an authorized local diagnostic FIG through both paths; the real file remains untracked and is not a test fixture. Evidence Both real-source paths retained all 12 visible graphics children with the opaque image last and the 11 overlay children in front. Temporary preview rasters confirmed the overlays were visible. Known limitations and follow-up Custom graphics classes still depend on MATLAB supporting their native parent transition. The portable data package remains narrower than the native preview and export path."},{"title":"Figure Studio removes source-reference knowledge","url":"history/records/2026/07/LK-20260716-figure-studio-source-boundary.html","kind":"history","section":"history","keywords":"LK-20260716-figure-studio-source-boundary 2026-07-16 94 refactor compatible labkit_FigureStudio_app LabKit Core Apps Runtime source boundary","text":"Figure Studio removes source-reference knowledge id: LK-20260716-figure-studio-source-boundary date: 2026-07-16 sequence: 94 type: refactor compatibility: compatible component: `labkit_FigureStudio_app` | `0.2.3 -> 0.2.4` scope: LabKit Core Apps scope: Runtime source boundary Context Figure Studio read both the current path and stored filename from the nested portable source reference. It repeated those reads in session reconstruction, actions, file-list presentation, and selection lookup. Decision and rationale Resolve source paths once through Runtime V2 at each workflow boundary. Derive the displayed filename from the resolved path so the App needs no knowledge of any portable-reference field. Changes Migrated FIG session reconstruction, action loading, file presentation, and selection lookup to `labkit.ui.runtime.sourcePaths`. Derived the opened-file status name through `fileparts`. Removed every direct portable-reference field read from Figure Studio. Preserved imported axes data, default style adoption, source order, current selection, editing, and export behavior. User and data impact FIG selection and display behave unchanged. Figure Studio now owns only how it uses a resolved FIG file; Runtime V2 owns how that file remains portable. Compatibility and migration No project or source-record field changed. Existing Figure Studio projects require no migration. Validation Source-axes and result-file unit tests cover import and export semantics. The hidden GUI suite covers empty startup, FIG addition and selection, style presentation, save/load, and output workflows. Evidence [Figure Studio](../../../../apps/labkit-core/figure-studio/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up The repository-wide portable-reference guard remains deferred until all remaining App families have migrated."},{"title":"File-panel layout stabilization","url":"history/records/2026/06/LK-20260630-file-panel-layout-stabilization.html","kind":"history","section":"history","keywords":"LK-20260630-file-panel-layout-stabilization 2026-06-30 19 fix compatible labkit.ui labkit.ui File-panel layout stabilization","text":"File-panel layout stabilization id: LK-20260630-file-panel-layout-stabilization date: 2026-06-30 sequence: 19 type: fix compatibility: compatible component: `labkit.ui` | `3.2.3 -> 3.2.4` component: `labkit.ui` | `3.2.4 -> 3.2.5` scope: File-panel layout stabilization Context The single-file panel allocated too much height to its rows and could render inconsistently as the containing app resized. This was especially noticeable in file-heavy apps, where the panel competed with analysis controls and plots. Decision and rationale Give the panel explicit, compact row sizing and protect that geometry with GUI layout tests. The change stayed in the shared file-panel builder because the same visual defect appeared wherever the component was used. Changes `labkit.ui` `3.2.3 -> 3.2.5` Stabilized and compacted single file-panel layout. User and data impact File names and actions occupied less vertical space, leaving more room for the workflow below them. The change affected layout only; selections and loaded file data were unchanged. Compatibility and migration App definitions and selected files required no conversion. The shared panel kept the same controls and callbacks with revised row geometry. Validation Both commits extended `GuiLayoutUiDeclarativeAppTest` with the expected panel geometry. Exact historical test commands were not recorded. Evidence Main commits `7f8df1cd` and `02b2f1b6`. Known limitations and follow-up Later runtime generations replaced this private UI 3.x builder, but retained the principle that shared components own and test their responsive geometry."},{"title":"File-panel migration","url":"history/records/2026/06/LK-20260624-file-panel-migration.html","kind":"history","section":"history","keywords":"LK-20260624-file-panel-migration 2026-06-24 12 refactor breaking labkit.dta labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app File-panel migration","text":"File-panel migration id: LK-20260624-file-panel-migration date: 2026-06-24 sequence: 12 type: refactor compatibility: breaking component: `labkit.dta` | `1.0.0 -> 2.0.0` component: `labkit.ui` | `2.2.1 -> 3.0.0` component: `labkit_DICPostprocess_app` | `1.0.1 -> 1.2.0` component: `labkit_DICPreprocess_app` | `1.0.1 -> 1.2.0` component: `labkit_ChronoOverlay_app` | `1.0.0 -> 1.2.0` component: `labkit_CIC_app` | `1.0.0 -> 1.2.0` component: `labkit_CSC_app` | `1.0.0 -> 1.2.0` component: `labkit_EIS_app` | `1.0.0 -> 1.2.0` component: `labkit_VTResistance_app` | `1.0.0 -> 1.2.0` component: `labkit_BatchImageCrop_app` | `1.0.0 -> 1.2.0` component: `labkit_CurvatureMeasurement_app` | `1.0.1 -> 1.2.0` component: `labkit_FocusStack_app` | `1.0.0 -> 1.2.0` component: `labkit_ImageEnhance_app` | `1.0.0 -> 1.2.0` component: `labkit_ImageMatch_app` | `1.0.0 -> 1.2.0` component: `labkit_NerveResponseAnalysis_app` | `1.0.0 -> 1.2.0` component: `labkit_ResponseReviewStats_app` | `1.0.0 -> 1.2.0` component: `labkit_RHSPreview_app` | `1.0.0 -> 1.2.0` component: `labkit_ECGPrint_app` | `1.0.0 -> 1.2.0` scope: File-panel migration Context Apps implemented file selection through separate task-input adapters, which produced inconsistent lists, selection events, and status feedback. The DTA session helper also coupled parsing to that older UI model. Decision and rationale Move supported apps to one reusable file-panel model and make DTA loading a GUI-free file/curve API. Accept the breaking package versions because retaining both task-input and file-panel paths would preserve ambiguous callback behavior. Changes `labkit.dta` `1.0.0 -> 2.0.0` `labkit.ui` `2.2.1 -> 3.0.0` All supported apps moved from `1.0.x` into the `1.2.0` workflow line. Replaced task inputs with file panels. Removed the old DTA session helper surface. User and data impact File lists, current selection, add/remove actions, and status display became consistent across the migrated apps. App code written against the removed task inputs or DTA session helpers required an update. Compatibility and migration This was a breaking workflow migration. Older app code expecting task inputs or the removed DTA session helpers needed migration. Validation Commit `b145c904` migrated app GUI workflows and package compatibility tests to the new file-panel and DTA APIs. Evidence Main commit `b145c904`. Known limitations and follow-up This first file-panel generation was later refined for append behavior, native dialog edge cases, and Runtime V2 events."},{"title":"Focus Stack adopts the compact App contract","url":"history/records/2026/07/LK-20260716-focus-stack-structure.html","kind":"history","section":"history","keywords":"LK-20260716-focus-stack-structure 2026-07-16 95 refactor compatible labkit_FocusStack_app Image Measurement App structure","text":"Focus Stack adopts the compact App contract id: LK-20260716-focus-stack-structure date: 2026-07-16 sequence: 95 type: refactor compatibility: compatible component: `labkit_FocusStack_app` | `1.5.1 -> 1.5.2` scope: Image Measurement scope: App structure Context Focus Stack split static metadata across `requirements.m` and `version.m`, spread a version-1 project over a generic lifecycle package, grouped three calculation concepts under `+appState`, and ran a startup callback only to fill an output path and emit an App-specific debug line. It also duplicated the portable-reference path loop in session, actions, and presentation. Decision and rationale Use the compact Runtime V2 contract: one product definition, one durable project specification, and one explicit session factory. Put calculation result shape, presets, and run fingerprinting beside the computation. Resolve output folders only when file registration or export actually needs them. Changes Consolidated command metadata, version, requirements, and optional capabilities in `definition.m`. Consolidated project creation and validation in `projectSpec.m`. Moved transient image reconstruction to root `createSession.m`. Moved three `+appState` helpers into their owning `+analysisRun` capability. Removed the metadata files, generic lifecycle/state packages, and redundant App startup callback. Replaced all direct portable-reference reads with the Runtime path accessor. User and data impact Focus loading, registration, fusion, previews, duplicate-run detection, project reopen, and exports keep the same scientific behavior. A new App no longer mutates its durable output folder during startup. After inputs are selected, output defaults remain source-adjacent as before. The App package loses six structural files and one generic package while its real workflow capabilities become easier to locate. Compatibility and migration The durable payload remains version 1 with identical fields, defaults, and validation. Existing projects require no migration. The removed startup debug line is replaced by the Runtime's standard debug-startup message. Validation Unit tests cover the definition/project/session contract, numerical fusion, registration, deterministic run fingerprints, summaries, readers, and invalid inputs. The hidden GUI test covers debug startup, file and folder import, fusion, presentation, export manifest, save/load reconstruction, and append. Evidence [Focus Stack](../../../../apps/image-measurement/focus-stack/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up The remaining Image Measurement Apps still use the older structural packages and will be reviewed individually rather than copied from this App blindly."},{"title":"Framework guides and function reference keep distinct routes","url":"history/records/2026/07/LK-20260717-framework-guide-and-function-routes.html","kind":"history","section":"history","keywords":"LK-20260717-framework-guide-and-function-routes 2026-07-17 134 fix compatible Documentation information architecture","text":"Framework guides and function reference keep distinct routes id: LK-20260717-framework-guide-and-function-routes date: 2026-07-17 sequence: 134 type: fix compatibility: compatible scope: Documentation information architecture Context An initial Framework documentation alignment also classified individual `labkit.ui.*` and `labkit.contract.*` API pages as Framework pages. Entering those pages from the global Functions index then changed the active top-level area, which mixed conceptual ownership with page type and made return paths hard to predict. Decision and rationale Keep conceptual and workflow guides under Framework. Keep every exact MATLAB function contract under Functions. Visible API group labels still explain that `labkit.ui` is the Framework implementation, but the top navigation remains stable while browsing function reference pages. Changes Moved the canonical compatibility guide to `framework/contracts.html`. Kept a tracked legacy page at `libraries/contracts/index.html` that links to the new guide and the Functions reference. Restored Functions ownership for all individual UI and contract API pages. Updated framework, library, and regression-test links to the canonical guide. User and data impact Readers now follow one predictable route for Framework guides and another for exact function syntax. Existing contract-guide bookmarks still reach a compatibility page. MATLAB code and scientific data are unchanged. Compatibility and migration The old guide URL remains as a compatibility landing page. Public MATLAB symbols remain unchanged. Validation Renderer regression verifies the Framework guide route, legacy landing page, and Functions-active runtime API page. `docsCheck` verifies the complete site. Evidence The generated Framework landing page links directly to `framework/contracts.html`, while `labkit.ui.runtime.launch` highlights Functions and labels its sibling group Framework Runtime. Known limitations and follow-up The legacy page is a visible handoff rather than an HTTP redirect because the tracked static-site renderer does not currently emit redirect responses."},{"title":"Framework owns UI and compatibility documentation","url":"history/records/2026/07/LK-20260717-framework-documentation-ownership.html","kind":"history","section":"history","keywords":"LK-20260717-framework-documentation-ownership 2026-07-17 133 docs compatible App Framework documentation","text":"Framework owns UI and compatibility documentation id: LK-20260717-framework-documentation-ownership date: 2026-07-17 sequence: 133 type: docs compatibility: compatible scope: App Framework documentation Context The documentation described `labkit.ui` as the App Framework but presented its public API and the compatibility contracts through the generic Functions area. The visible information architecture therefore disagreed with the framework terminology used by app development guides. Decision and rationale Make Framework the documentation owner for `labkit.ui.*` and `labkit.contract.*`. Compatibility requirements belong in the Framework because App definitions and startup consume them. Keep the stable `labkit.contract` MATLAB namespace because it checks UI and domain facades alike; moving it below `labkit.ui` would create a misleading dependency and break existing App definitions. Changes Added compatibility contracts as a Framework sidebar branch. Classified UI and contract API pages under the Framework top navigation. Replaced raw UI package headings with visible Framework API labels while retaining fully qualified MATLAB symbols. Removed the separate Contracts entry from the Functions guide table. User and data impact Readers now enter framework runtime, layout, plotting, interaction, debugging, and compatibility material through one consistent Framework route. MATLAB calls, saved projects, scientific results, and URLs remain compatible. Compatibility and migration No code migration is required. Existing `labkit.ui.*` and `labkit.contract.*` symbols are unchanged. Validation Renderer regression tests verify Framework ownership for the contracts guide and a runtime API page. `docsCheck` rebuilds and compares the complete site. Evidence Generated UI and contract pages highlight Framework in the product navigation, and the Framework landing sidebar links the compatibility guide. Known limitations and follow-up The global API reference still indexes all public symbols together so exact MATLAB functions remain searchable from one place."},{"title":"Framework public APIs become an explicit last resort","url":"history/records/2026/07/LK-20260720-public-api-escalation-order.html","kind":"history","section":"history","keywords":"LK-20260720-public-api-escalation-order 2026-07-20 144 docs compatible Architecture guidance Agent skills","text":"Framework public APIs become an explicit last resort id: LK-20260720-public-api-escalation-order date: 2026-07-20 sequence: 144 type: docs compatibility: compatible scope: Architecture guidance scope: Agent skills Context A convenient framework helper can appear attractive for one App-specific need, but every public name becomes a long-lived compatibility and documentation commitment. Conversely, forcing unrelated behavior into an existing API can turn a focused contract into an ambiguous option bucket. Decision and rationale Use a consistent escalation order for new App behavior: keep it App-local, extend an existing focused API when the addition is natural, add private framework/runtime capability when shared implementation does not require an App-authored contract, and add a new public API only for stable use by multiple Apps or when the nearest existing API would otherwise lose a clear single purpose. This makes a new public API the final solution without prohibiting one when a genuine reusable boundary has emerged. Changes Added the escalation order to the root, framework, and App agent contracts. Updated the App builder and boundary guard skills to require evidence for multiple consumers or an anti-bucket clarity need before introducing a new public name. Updated the documentation maintainer skill to distinguish documentation of an existing focused extension from review of a genuinely new public surface. User and data impact Runtime behavior, public signatures, App calculations, projects, and exports are unchanged. The rule affects future design choices and review evidence. Compatibility and migration No additional migration applies beyond the compatibility information in the preceding impact section. Validation Skill package validation covers every edited skill. Documentation history rendering and consistency checks cover this record. Repository searches confirm the escalation order appears at the three ownership layers and in the relevant skills. Evidence The validation details above are the supporting evidence for this record. Known limitations and follow-up When a proposed public API crosses the stated threshold, record its consumers, ownership rationale, alternatives considered, and compatibility contract in the component history."},{"title":"Gait Analysis active-swing workflow","url":"history/records/2026/07/LK-20260716-gait-analysis-active-swing-workflow.html","kind":"history","section":"history","keywords":"LK-20260716-gait-analysis-active-swing-workflow 2026-07-16 71 feat breaking labkit_GaitAnalysis_app Video Marker input contract treadmill swing segmentation gait visualization and exports","text":"Gait Analysis active-swing workflow id: LK-20260716-gait-analysis-active-swing-workflow date: 2026-07-16 sequence: 71 type: feat compatibility: breaking component: `labkit_GaitAnalysis_app` | `1.1.1 -> 2.0.0` scope: Video Marker input contract scope: treadmill swing segmentation scope: gait visualization and exports Context The migrated Gait app accepted loosely shaped coordinate files but did not recover the legacy workflow's step segmentation, per-step skeleton report, or complete translation and angle measurements. A coordinate file alone also could not prove its frame rate, skeleton order, or calibration. Decision and rationale Treat a current Video Marker payload-version-2 project or autosave as the sole file input. It is the first durable artifact that owns coordinates, timing, skeleton, calibration, and annotation provenance together. Segment the legacy treadmill active swing from a prominent foot-X maximum (lift-off) to the following minimum (landing), including a final completed swing that has no later lift-off. Changes Load only the named `labkitProject` variable and reject generic tables, arbitrary MAT variables, legacy marker payloads, and missing frame rate. Show all overlaid skeleton trajectories immediately after import. Detect active swings with app-owned prominence, peak-height, and temporal separation logic; compute cycle/stance measures when a following lift-off exists. Present one selected swing with connected landmarks, joint/segment traces, five endpoint translations, and joint minimum, maximum, and range of motion. Export per-frame, coordinate, step, summary, and provenance tables with lift-off/landing and `swing_time_s` terminology. Migrate version-1 Gait option names and invalidate its scientifically incompatible cached result. User and data impact Users first inspect all trajectories, then run analysis and move between segmented swings. Existing Gait project settings are migrated, but old cached results are recalculated. Older or generic pose files must be converted by opening and saving the source in current Video Marker. Compatibility and migration This is an intentional input and output-schema break. The durable project migration preserves equivalent thresholds while renaming stride/contact-era fields to active-swing terms. Video Marker project payload version 2 is required. Validation Focused unit tests cover source metadata recovery, rejection of incomplete and legacy MAT files, lift-off/landing pairs, retention of the final completed swing, migration of old option names, scientific table fields, and exports. The focused GUI test covers trajectory orientation, analysis, step preview, export, and project reopen. Evidence [Gait Analysis](../../../../apps/gait/gait-analysis/README.md) documents the source, calculation, visualization, and export contracts. [Video Marker](../../../../apps/image-measurement/video-marker/README.md) documents the durable payload used as input. Known limitations and follow-up The detector represents image-kinematic treadmill events, not force-plate contact. Frame annotation status is preserved but is not yet an automatic step exclusion rule."},{"title":"Gait Analysis app","url":"history/records/2026/07/LK-20260714-gait-analysis-app.html","kind":"history","section":"history","keywords":"LK-20260714-gait-analysis-app 2026-07-14 55 feat compatible labkit_GaitAnalysis_app Gait Analysis app","text":"Gait Analysis app id: LK-20260714-gait-analysis-app date: 2026-07-14 sequence: 55 type: feat compatibility: compatible component: `labkit_GaitAnalysis_app` | `new -> 1.0.0` scope: Gait Analysis app Context Existing gait work used a script chain after pose tracking: import coordinates, smooth marker traces, make per-step figures, compute step and joint metrics, select useful steps, and export tables for downstream statistics. That work belongs in its own app family because the downstream task is not image annotation, signal import, or electrochemistry; it is gait-specific pose analysis from already tracked coordinates. Decision and rationale Add an independent Gait Analysis app instead of extending Video Marker or recreating a model-training workflow. The app accepts several coordinate-table shapes, keeps gait event detection and metric definitions app-local, and exports simple CSV tables that can be consumed by plotting or statistical programs. Changes Added `labkit_GaitAnalysis_app` under the new Gait family. Added CSV/TSV/TXT and MAT pose-coordinate import, including generic `point_x`/`point_y` and LabKit `point__x`/`point__y` column shapes. Added smoothing, foot-relative step-event detection, hip/knee/ankle angle calculation, segment lengths, per-step translations, stride length, step time, ROM, summary metrics, and trajectory/angle/step-event previews. Added CSV set export for frame metrics, step metrics, summary metrics, and per-frame coordinates that keep raw pixel columns alongside optional scale-calibrated and first-frame-origin-shifted columns. User and data impact Users can analyze gait from multiple pose-coordinate sources without tying the workflow to a specific tracking model. The exported tables are plain CSV and separate frame-level, coordinate, step-level, and summary data for downstream overlay, plotting, or statistics. Compatibility and migration The app is additive and does not change Video Marker, image measurement apps, public `+labkit` facades, or existing exports. Existing script outputs can be imported when they provide wide coordinate columns or MAT `coords` and `pointNames`. Validation `GaitAnalysisTest` covers coordinate import, synthetic step detection, metric tables, MAT import, coordinate export calibration/origin semantics, coordinate CSV readback, and CSV set export. `GuiLayoutGaitAnalysisTest` covers the hidden GUI launch and semantic control contract. These tests were added with the app in commit `49863964`. Evidence Initial Gait Analysis app `49863964`. Known limitations and follow-up The first version analyzes one tracked subject at a time and does not perform tracking, model training, group-level statistics, EMG/CAP synchronization, multi-limb phase analysis, or automatic step quality classification."},{"title":"Gait Analysis keeps schema history in one project contract","url":"history/records/2026/07/LK-20260716-gait-analysis-structure.html","kind":"history","section":"history","keywords":"LK-20260716-gait-analysis-structure 2026-07-16 104 refactor compatible labkit_GaitAnalysis_app Gait App structure","text":"Gait Analysis keeps schema history in one project contract id: LK-20260716-gait-analysis-structure date: 2026-07-16 sequence: 104 type: refactor compatibility: compatible component: `labkit_GaitAnalysis_app` | `2.0.3 -> 2.0.4` scope: Gait scope: App structure Context Gait Analysis spread creation, validation, session reconstruction, and two ordered schema upgrades through a generic lifecycle package. Its generic state package actually contained four analysis concepts: defaults, source-derived options, result construction, and duplicate-run fingerprints. Session and presentation code also inspected the Runtime's nested source-reference fields. Decision and rationale Concentrate project history behind one `projectSpec.m`, keep transient pose reconstruction in root `createSession.m`, and assign all former state helpers to `+analysisRun`. This preserves the real complexity—Video Marker parsing, step segmentation, kinematics, QC, and exports—while removing structural categories that did not explain the workflow. Changes Consolidated product metadata, version, requirements, layout, actions, presentation, renderer, and debug capability in `definition.m`. Replaced two public migration files with one migration callback that selects the version-1 or version-2 transformation from `fromVersion`. Moved default options, pose-derived option resolution, empty results, and deterministic task fingerprints from `+appState` to `+analysisRun`. Replaced direct portable-reference access with semantic `sourcePaths` lookup in session reconstruction and presentation. Removed generic lifecycle/state packages and separate requirement/version files, and updated GUI-free documentation calls to the owning package. User and data impact Current Video Marker MAT loading, full-trajectory inspection, active-swing segmentation, one-step review, joint angles, translations, timing, QC, duplicate-run detection, CSV export, project save, and project reopen retain their behavior. The image-coordinate Y direction and time-series coordinate direction remain deliberately distinct. Developers can now follow project history through one entry and find all analysis policy under the package that owns the scientific workflow. Compatibility and migration Durable schema version 3 is unchanged. Version-1 option renames and result invalidation still run before the version-2 source collection upgrade. Runtime V2 now owns the loop and validates the resulting current payload. Validation Focused tests cover current Video Marker input, timing/scale/role extraction, active-swing segmentation, final-swing retention, gait parameters, CSV round-trip, and both historical migrations. The hidden GUI workflow covers MAT import, trajectory preview, analysis, export, project save, and decoded pose reconstruction after reopen. Evidence [Gait Analysis](../../../../apps/gait/gait-analysis/README.md) [Video Marker](../../../../apps/image-measurement/video-marker/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Automated tests do not establish scientific validity for recordings outside the documented treadmill model or replace manual inspection of tracked points and segmented events. Neurophysiology and wearable Apps with generic lifecycle packages remain scheduled for the same review."},{"title":"Gait consumes the Video Marker file contract without a sibling App dependency","url":"history/records/2026/07/LK-20260717-gait-app-path-isolation.html","kind":"history","section":"history","keywords":"LK-20260717-gait-app-path-isolation 2026-07-17 124 fix compatible labkit_GaitAnalysis_app Gait App packaging Video Marker file contract","text":"Gait consumes the Video Marker file contract without a sibling App dependency id: LK-20260717-gait-app-path-isolation date: 2026-07-17 sequence: 124 type: fix compatibility: compatible component: `labkit_GaitAnalysis_app` | `2.0.7 -> 2.0.8` scope: Gait scope: App packaging scope: Video Marker file contract Context Gait Analysis correctly parsed saved Video Marker MAT documents in production, but its synthetic debug writer created those documents by calling `video_marker.projectSpec`, `video_marker.skeletonDefinition`, and `video_marker.frameAnnotations`. Tests added every App root to the MATLAB path, while the launcher adds only the selected App root. Debug startup could therefore pass tests and fail in a real isolated launch. Decision and rationale Treat the saved `labkitProject` payload as the boundary between the producer and consumer. Gait owns its parser, diagnostics, and synthetic consumer fixture. Video Marker owns serialization and schema validation. One explicit integration test may load both Apps to prove their current file contracts agree, but neither Gait production nor debug code may call the Video Marker package. Changes Rebuilt the Gait debug sample from the documented payload fields without loading Video Marker source code. Split consumer parser tests from a producer-consumer integration test that constructs a current Video Marker project, validates it, saves it, and reads it through Gait. Added an isolated-path debug test using only the repository root and Gait App root. Added a repository guardrail that rejects executable calls from one App package into a sibling App package while allowing documentation references and integration tests. Documented the saved-data boundary in the App development guide and Gait manual. User and data impact Gait debug startup and its packaged App behavior no longer depend on every public App being present on the MATLAB path. Users continue to open the same current Video Marker project and autosave MAT files; parsing, timing, calibration, gait calculations, and exports are unchanged. Developers receive an immediate guardrail failure if a shared test path hides a new sibling-App runtime dependency. Compatibility and migration No project or output migration is required. Video Marker payload version 2 remains the accepted input contract. Validation Focused validation covers isolated debug sample generation, consumer parsing, current Video Marker producer-to-Gait import, Gait calculations and hidden GUI workflow, and the App package boundary guardrail. Evidence [Gait Analysis](../../../../apps/gait/gait-analysis/README.md) [Video Marker](../../../../apps/image-measurement/video-marker/README.md) [App Development](../../../../development/build-apps/app-development.md#cross-app-data-contracts) Known limitations and follow-up The integration test protects the current saved schema, not scientific validity of manually marked trajectories. Those data and workflow checks remain App-owned."},{"title":"Gait trajectory image-coordinate preview","url":"history/records/2026/07/LK-20260716-gait-image-coordinates.html","kind":"history","section":"history","keywords":"LK-20260716-gait-image-coordinates 2026-07-16 67 fix compatible labkit_GaitAnalysis_app trajectory preview","text":"Gait trajectory image-coordinate preview id: LK-20260716-gait-image-coordinates date: 2026-07-16 sequence: 67 type: fix compatibility: compatible component: `labkit_GaitAnalysis_app` | `1.1.0 -> 1.1.1` scope: trajectory preview Context Marker coordinates use the image convention with an upper-left origin and Y increasing downward. Gait Analysis plotted those values on MATLAB's default Cartesian axes, so the trajectory preview appeared vertically flipped relative to the source video. Decision and rationale Preserve the imported coordinate values and scientific calculations. Reverse only the trajectory preview's Y axis so its visual orientation matches Video Marker and Image Marker. Time-series angle and step plots explicitly retain the conventional upward Y direction. Changes Render trajectory previews with a reversed Y axis. Restore the normal Y direction when switching to Angles or Steps. Document the preview coordinate convention. User and data impact Tracked motion now appears in the same orientation as the source image. Stored coordinates, calculations, tables, and exports are unchanged. Compatibility and migration The change is display-only and requires no project or data migration. Validation The hidden Gait Analysis workflow test checks both trajectory and time-series axis directions while exercising source load and analysis. Evidence [Gait Analysis](../../../../apps/gait/gait-analysis/README.md) documents the image-coordinate preview convention. Known limitations and follow-up The preview assumes imported marker coordinates follow the documented image coordinate convention. Generic coordinate files with a Cartesian convention must be converted by their producer before import."},{"title":"Headless validation follows current documentation and App contracts","url":"history/records/2026/07/LK-20260719-headless-validation-repair.html","kind":"history","section":"history","keywords":"LK-20260719-headless-validation-repair 2026-07-19 137 fix compatible labkit_TTestWizard_app Continuous integration Documentation validation Statistics","text":"Headless validation follows current documentation and App contracts id: LK-20260719-headless-validation-repair date: 2026-07-19 sequence: 137 type: fix compatibility: compatible component: `labkit_TTestWizard_app` | `1.0.0 -> 1.0.1` scope: Continuous integration scope: Documentation validation scope: Statistics Context The first main-branch validation after the path-derived documentation change still asserted several retired documentation paths. The same run exposed T-Test Wizard code-quality findings and a framework GUI test file that had grown beyond its review budget. Decision and rationale Align validation with the current path-owned documentation structure and keep Runtime-owned empty session buckets out of App factories. Resolve the static analysis findings without changing calculations, export values, or visible workflow behavior. Split the workspace-specific GUI coverage by capability so each test file remains focused. Changes Updated documentation guardrails to use the current testing, Runtime, and complete-App guide paths. Removed an empty `view` placeholder that Runtime already supplies. Replaced dynamic array growth in group-label and group-reassignment helpers with bounded collection. Centralized the box-plot label and documented the plot-jitter and significance-display constants. Split workspace-page and dynamic-table GUI coverage into its own focused test file. User and data impact T-Test Wizard calculations, project data, CSV values, plots, and workflows are unchanged. The App version advances to 1.0.1 to record the internal validation repair. Compatibility and migration Existing version-1 projects remain compatible and require no data migration. Runtime continues to provide `selection`, `workflow`, `view`, and `cache` in the final session state. Validation Focused contract and T-Test core tests cover the original headless failures. Hidden GUI tests cover the T-Test workflow and the extracted Runtime workspace coverage. Documentation rendering and changed-file gates validate the final main-branch handoff. Evidence [T-Test Wizard](../../../../apps/statistics/ttest-wizard/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [Testing LabKit](../../../../development/maintain-and-release/testing.md) Known limitations and follow-up Interactive native-dialog behavior remains a developer-led manual validation responsibility; hidden GUI automation does not replace it."},{"title":"History records use one canonical authored format","url":"history/records/2026/07/LK-20260721-canonical-history-record-format.html","kind":"history","section":"history","keywords":"LK-20260721-canonical-history-record-format 2026-07-21 149 docs compatible Project History Documentation Search","text":"History records use one canonical authored format id: LK-20260721-canonical-history-record-format date: 2026-07-21 sequence: 149 type: docs compatibility: compatible scope: Project History scope: Documentation Search Context History records mixed a transport-oriented schema marker with several related but inconsistent metadata conventions. Authors had to infer valid fields and values from renderer internals and agent guidance. Decision and rationale Use one compact, authored record format without a schema field. A single public format page defines every legal field, value, ordering rule, and narrative section so a record can be written and reviewed from repository documentation. Changes Rewrote every existing record into the canonical metadata form, preserved its identity, date, sequence, narrative, and component history links, and added a strict renderer parser. Scopes now feed the documentation search index. User and data impact Readers retain the complete history timeline and component links while gaining more useful search terms. This documentation-only change does not alter saved projects, experimental data, or App behavior. Compatibility and migration The source format changes incompatibly for record authors: remove `schema` and replace an introduction entry with a `component` transition using `new ->`. Existing records are migrated in this same change, so no compatibility reader is retained. Validation The documentation renderer validates every migrated record, rebuilds the site, and documentation guardrails verify the canonical source and generated output. Evidence The renderer parser is the executable enforcement of the published format; the record format page provides its human-readable counterpart. Known limitations and follow-up No known follow-up is required. Future history changes use this format directly rather than adding compatibility metadata variants."},{"title":"Image App project validation ownership","url":"history/records/2026/07/LK-20260716-image-project-validation-ownership.html","kind":"history","section":"history","keywords":"LK-20260716-image-project-validation-ownership 2026-07-16 119 refactor compatible labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_VideoMarker_app image App project schemas App maintenance cost","text":"Image App project validation ownership id: LK-20260716-image-project-validation-ownership date: 2026-07-16 sequence: 119 type: refactor compatibility: compatible component: `labkit_BatchImageCrop_app` | `1.7.4 -> 1.7.5` component: `labkit_CurvatureMeasurement_app` | `1.4.4 -> 1.4.5` component: `labkit_FLIRThermal_app` | `1.4.4 -> 1.4.5` component: `labkit_FocusStack_app` | `1.5.3 -> 1.5.4` component: `labkit_ImageEnhance_app` | `1.6.4 -> 1.6.5` component: `labkit_ImageMatch_app` | `1.6.4 -> 1.6.5` component: `labkit_VideoMarker_app` | `1.5.3 -> 1.5.4` scope: image App project schemas scope: App maintenance cost Context The seven image workflow validators repeated Runtime's canonical project-bucket checks and, in six cases, the standard portable source-record field list. Those checks obscured the App-specific rules that actually matter: crop task relationships, parameter ranges, annotation shapes, video metadata, skeleton dimensions, and result schemas. Decision and rationale Keep the existence of each App's required source collection and every domain-specific relationship in `projectSpec.m`. Rely on Runtime for the five canonical bucket structs and the internal shape of every supplied source record. This preserves strict malformed-project rejection while making each validator read as its App schema. Changes Removed 71 net lines of repeated Runtime structure checks from the seven image App project specifications. Preserved required `inputs.sources` fields and all item/source, annotation/source, skeleton/frame, parameter, and result constraints. Added a GUI-free contract that accepts all seven default projects and rejects each project when its App-required source collection is removed. User and data impact Valid projects, migrations, image calculations, annotations, and exports are unchanged. Malformed source records continue to fail in Runtime; malformed App fields continue to fail in the owning App validator. Compatibility and migration No payload format changed and no migration is required. The refactor changes which layer reports framework-owned structure failures, not which valid data the Apps accept. Validation The focused project-spec contract covers default acceptance and missing-source rejection for every affected App. Existing focused unit and hidden-GUI tests cover the domain relationships and representative load, edit, analyze, and export workflows. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) defines canonical project and source validation. Each affected [Image Measurement App](../../../../apps/image-measurement/README.md) manual lists its remaining project and session responsibilities. Known limitations and follow-up This change does not shorten action handlers or scientific workflow code. Those remain App-owned unless a separately measured repeated behavior proves to be stable and domain-neutral."},{"title":"Image Apps stop creating invalid placeholder outputs","url":"history/records/2026/07/LK-20260716-image-manifest-output-arrays.html","kind":"history","section":"history","keywords":"LK-20260716-image-manifest-output-arrays 2026-07-16 80 fix compatible labkit_BatchImageCrop_app labkit_FLIRThermal_app labkit_ImageEnhance_app labkit_ImageMatch_app Image Measurement Result manifests","text":"Image Apps stop creating invalid placeholder outputs id: LK-20260716-image-manifest-output-arrays date: 2026-07-16 sequence: 80 type: fix compatibility: compatible component: `labkit_BatchImageCrop_app` | `1.7.1 -> 1.7.2` component: `labkit_FLIRThermal_app` | `1.4.1 -> 1.4.2` component: `labkit_ImageEnhance_app` | `1.6.1 -> 1.6.2` component: `labkit_ImageMatch_app` | `1.6.1 -> 1.6.2` scope: Image Measurement scope: Result manifests Context Four image Apps preallocated variable-length result arrays by first asking the Runtime output factory to create a record with an empty ID. Runtime V2 rejects empty result IDs, so otherwise valid export workflows could stop before their standard manifest was written. Decision and rationale Use the canonical empty result array introduced by `labkit.ui` and append only validated real outputs. This preserves strict IDs without requiring each App to duplicate the manifest struct shape. Changes Updated Batch Crop crop outputs. Updated FLIR image, colorbar, and temperature-CSV outputs. Updated Image Enhance batch outputs. Updated Image Match batch outputs. User and data impact The exported images, numeric CSV data, filenames, roles, statuses, and manifest schemas are unchanged. Exports no longer fail during internal output-array initialization. Compatibility and migration No saved project or export schema migration is required. Existing result files remain readable. Validation Each affected App's hidden synthetic GUI export workflow verifies its domain output plus the standard LabKit manifest. Version and component-history guardrails cover all four products. Evidence [Batch Crop](../../../../apps/image-measurement/batch-crop/README.md) [FLIR Thermal](../../../../apps/image-measurement/flir-thermal/README.md) [Image Enhance](../../../../apps/image-measurement/image-enhance/README.md) [Image Match](../../../../apps/image-measurement/image-match/README.md) Known limitations and follow-up The Apps still need their separate single-definition and projectSpec reviews; this record only fixes the shared manifest construction defect."},{"title":"Image Enhance assigns state helpers to workflow capabilities","url":"history/records/2026/07/LK-20260716-image-enhance-structure.html","kind":"history","section":"history","keywords":"LK-20260716-image-enhance-structure 2026-07-16 99 refactor compatible labkit_ImageEnhance_app Image Measurement App structure","text":"Image Enhance assigns state helpers to workflow capabilities id: LK-20260716-image-enhance-structure date: 2026-07-16 sequence: 99 type: refactor compatibility: compatible component: `labkit_ImageEnhance_app` | `1.6.2 -> 1.6.3` scope: Image Measurement scope: App structure Context Image Enhance split static product metadata across files, spread a version-1 project over a generic lifecycle package, and placed decoded items, durable annotations, numerical histories, preview scaling, UI normalization, and export fingerprints together under `+appState`. Source reconstruction and presentation also read nested portable-reference fields directly. Decision and rationale Use the compact Runtime V2 definition and project contracts, then assign each remaining concept to the workflow capability that owns its behavior. Preserve the important preview/export boundary: pixel-radius parameters scale for the downsampled preview while full-size export continues to use source coordinates. Changes Consolidated product metadata, version, requirements, and optional capabilities in `definition.m`. Consolidated durable creation and validation in `projectSpec.m` and moved transient reconstruction to root `createSession.m`. Assigned decoded items and lazy selected-image loading to `+sourceFiles`, histories and preview replay to `+analysisRun`, durable per-image data to `+enhancementAnnotations`, UI value clamping to `+userInterface`, and export fingerprints to `+resultFiles`. Removed separate metadata files, generic lifecycle/state packages, and the redundant App startup callback. Replaced direct portable-reference access with the Runtime path accessor. Corrected the GUI-free manual example to write the first returned image from the documented cell-array result. User and data impact Shared and per-image histories, white ROI calibration, pending previews, preview-coordinate radius scaling, original-resolution processing, duplicate export detection, project reopen, and outputs keep their existing behavior. Empty launch no longer chooses an output folder; importing sources retains the source-adjacent default. Developers can locate source decoding, calculations, durable annotations, and exports without learning one generic state package. Compatibility and migration The durable payload remains version 1 with identical fields and defaults, so existing projects require no migration. The Runtime's standard debug-startup message replaces the removed App-specific line. Validation The focused unit suite covers numerical tools, white ROI behavior, preview radius scaling, source reading, full-size exports, manifests, per-image steps, task fingerprints, and project/presenter contracts. The hidden GUI workflow covers file append and selection, independent histories, tool application, export, save/load, and transient cache reconstruction. Evidence [Image Enhance](../../../../apps/image-measurement/image-enhance/README.md) [Image Library](../../../../libraries/image/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Other Apps still using generic lifecycle/state packages will be reviewed individually. Automated GUI tests do not replace manual judgment of visual quality, ROI pointer feel, or enhancement suitability for quantitative images."},{"title":"Image Match adopts capability-owned structure","url":"history/records/2026/07/LK-20260716-image-match-structure.html","kind":"history","section":"history","keywords":"LK-20260716-image-match-structure 2026-07-16 96 refactor compatible labkit_ImageMatch_app Image Measurement App structure","text":"Image Match adopts capability-owned structure id: LK-20260716-image-match-structure date: 2026-07-16 sequence: 96 type: refactor compatibility: compatible component: `labkit_ImageMatch_app` | `1.6.2 -> 1.6.3` scope: Image Measurement scope: App structure Context Image Match split metadata and project lifecycle across eight structural files, used an App startup callback only for an output-folder default and debug line, and grouped unrelated source, analysis, and export structures under `+appState`. Session, actions, and presentation also read portable-reference path fields directly. Decision and rationale Adopt one definition, one project spec, and one session factory. Place each data constructor beside the capability that owns its meaning: loaded image items with source reading, match steps with analysis, and idempotent export tasks with result writing. Changes Consolidated command metadata, version, requirements, and optional capabilities in `definition.m`. Consolidated version-1 project creation and validation in `projectSpec.m`. Moved selected-image reconstruction to root `createSession.m`. Replaced `+appState` with capability-owned source, analysis, and result functions. Removed the metadata files, generic lifecycle package, and redundant startup callback. Replaced all portable-reference field reads with the Runtime path accessor. Corrected the GUI-free manual example to use the real `applyPipeline` argument order and cell output. User and data impact Reference/source selection, lazy preview loading, match history, calculation, duplicate-export detection, project reopen, and export formats behave unchanged. A new project no longer writes an environment-specific output path during startup; source selection still establishes the same adjacent default. The directory now answers where an item, step, or export task belongs without requiring knowledge of a generic state layer. Compatibility and migration The durable payload remains version 1 with identical fields and validation. Existing Image Match projects require no migration. Validation Unit tests cover the definition/project/session contract, matching methods, pipeline replay, preview scaling, result tables, export formats, manifests, and task fingerprints. The hidden GUI suite covers reference/source loading, selection, history, preview, export, and save/load workflows. Evidence [Image Match](../../../../apps/image-measurement/image-match/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Other Image Measurement Apps retain older lifecycle or state packages and will be reviewed against their own capabilities."},{"title":"Image app workflow improvements","url":"history/records/2026/07/LK-20260701-image-app-workflow-improvements.html","kind":"history","section":"history","keywords":"LK-20260701-image-app-workflow-improvements 2026-07-01 27 feat compatible labkit_launcher labkit.image labkit.ui labkit.ui labkit_BatchImageCrop_app labkit_BatchImageCrop_app labkit_FLIRThermal_app labkit_FLIRThermal_app labkit_ImageEnhance_app labkit_ImageMatch_app Image app workflow improvements","text":"Image app workflow improvements id: LK-20260701-image-app-workflow-improvements date: 2026-07-01 sequence: 27 type: feat compatibility: compatible component: `labkit_launcher` | `1.1.5 -> 1.1.6` component: `labkit.image` | `1.0.0 -> 1.1.0` component: `labkit.ui` | `3.2.10 -> 3.3.0` component: `labkit.ui` | `3.3.0 -> 3.3.1` component: `labkit_BatchImageCrop_app` | `1.4.0 -> 1.5.0` component: `labkit_BatchImageCrop_app` | `1.5.0 -> 1.5.1` component: `labkit_FLIRThermal_app` | `1.0.0 -> 1.1.0` component: `labkit_FLIRThermal_app` | `1.1.0 -> 1.1.2` component: `labkit_ImageEnhance_app` | `1.4.0 -> 1.4.1` component: `labkit_ImageMatch_app` | `1.4.0 -> 1.4.1` scope: Image app workflow improvements Context Image apps used full-resolution data for several previews even when the screen could not display that detail. Controls also accepted ranges that were awkward for the current image, and FLIR point and ROI measurements were not yet a complete direct-manipulation workflow. Decision and rationale Set an explicit preview budget, derive sensible control bounds from the loaded image, and preserve full-resolution data for calculations and exports. Expand the FLIR app around point and ROI temperature tools rather than adding more separate analysis dialogs. Changes `labkit.image` `1.0.0 -> 1.1.0` `labkit.ui` `3.2.10 -> 3.3.1` Batch Crop `1.4.0 -> 1.5.1` FLIR Thermal `1.0.0 -> 1.1.2` `labkit_launcher` `1.1.5 -> 1.1.6` Added preview-budget helpers. Improved image app range and preview controls. Improved image measurement workflows. User and data impact Large images produced bounded previews while exports continued to use source resolution. Batch Crop controls reflected the crop and scale being edited, and FLIR users could place temperature points or regions directly on the image and read their values in the detail panel. Compatibility and migration Existing image inputs and app exports remained valid. Preview budgeting changed display resolution only; calculations and exports continued to use the source data required by each workflow. Validation The two commits expanded Batch Crop export tests, FLIR operation and layout tests, image-facade preview tests, busy-state tests, scale-bar gesture checks, and launcher coverage. Exact historical commands were not recorded. Evidence Main commits `15a798ba` and `70bfcfd4`. Known limitations and follow-up Preview budgeting improved responsiveness but did not by itself remove every eager image read. Batch Crop file selection was made lazy in the following profiling work."},{"title":"Interactive recovery of missing project sources","url":"history/records/2026/07/LK-20260716-runtime-source-relink.html","kind":"history","section":"history","keywords":"LK-20260716-runtime-source-relink 2026-07-16 66 fix compatible labkit.ui project loading portable source references","text":"Interactive recovery of missing project sources id: LK-20260716-runtime-source-relink date: 2026-07-16 sequence: 66 type: fix compatibility: compatible component: `labkit.ui` | `6.0.1 -> 6.0.2` scope: project loading scope: portable source references Context Saved projects could describe required external files with portable source records, but an unresolved path produced a framework error unless the owning app implemented the advanced `Project.RelinkSources` hook. Production apps using standard source records therefore had no common recovery interaction when a project moved between folders, drives, or operating systems. Decision and rationale Make missing-file recovery the default Runtime V2 behavior for canonical source records. The runtime already owns project loading, injected dialogs, and transactional state replacement, so it can provide one consistent prompt without duplicating native chooser code in every app. The advanced app hook remains available for nonstandard source schemas. Changes Report the saved filename and source role when automatic resolution fails. Let the user locate each missing required file with one native file chooser. Rebuild the selected source reference relative to the loaded project before constructing the app session. Mark a successfully repaired document as unsaved so the replacement path can be retained on the next save. Mark migrated payloads, snapshots, and declared legacy variables as unsaved; **Save State** then upgrades the opened MAT path to the current project format through the existing atomic replacement. Treat cancellation as an atomic load cancellation without changing the live project or view. User and data impact Projects whose external files remain in their recorded locations open exactly as before. When a required file moved, the user can locate it instead of seeing only an unresolved-source error. The runtime never searches arbitrary folders or silently substitutes a different file. Merely opening an old document does not rewrite it; saving the migrated document upgrades that same path. Compatibility and migration The change is compatible with current project envelopes, declared legacy imports, and existing custom `Project.RelinkSources` callbacks. Selecting a replacement updates only the candidate project; saving writes the current project format. Validation The hidden Runtime V2 project test covers successful default relinking, relative-reference rebuilding, dirty-document state, cancellation rollback, and the existing custom relink hook. Evidence [Runtime and lifecycle](../../../../framework/guides/runtime.md) documents the default missing-source interaction. Runtime source resolution reruns before fresh-session construction and state commit. Known limitations and follow-up The default flow asks once for each unresolved source. Apps with a specialized multi-file schema may continue to provide a custom relinking callback."},{"title":"LabKit name and the first multi-domain app families","url":"history/records/2026/05/LK-20260530-app-family-expansion.html","kind":"history","section":"history","keywords":"LK-20260530-app-family-expansion 2026-05-30 3 feat compatible historical project evolution","text":"LabKit name and the first multi-domain app families id: LK-20260530-app-family-expansion date: 2026-05-30 sequence: 3 type: feat compatibility: compatible scope: historical project evolution Context By the end of the electrochem extraction, the repository had reusable DTA operations and several app entry points, but its naming and package layout still reflected the original Gamry workbench. It was not yet clear whether the design could serve workflows with different data, interaction, and visualization needs. Decision and rationale Rename the project LabKit and treat apps, rather than one scientific domain, as the main deliverables. Keep a limited set of reusable packages underneath them, then exercise that structure with image registration, region editing, curvature measurement, wearable data import, and ECG viewing. The purpose was not to turn LabKit into one analysis program. It was to make a common MATLAB foundation useful to several independent laboratory tools without erasing the workflow decisions that made each tool understandable. Changes Renamed the workbench namespace to `labkit` and reduced the public package surface to app-facing UI and domain operations. Standardized the basic workbench shell and DTA file panels across the electrochem apps. Added DIC preprocessing and postprocessing workflows with iterative crop, mask, registration, zoom, and preview interactions. Added the Curvature Measurement app and reused its anchor-curve editor across image workflows where the interaction was genuinely the same. Added a biosignal facade and the ECG Print app, including wearable CSV import and signal-column diagnostics. Added MATLAB CI and reorganized tests by source responsibility. User and data impact LabKit now served electrochem, image, and biosignal work from distinct app entry points. Image users gained direct manipulation of regions and anchors; biosignal users gained a viewer for imported wearable recordings. Existing DTA files remained external inputs and were not converted into a central project format. Compatibility and migration The namespace rename was an implementation migration for repository code. The new image and biosignal apps were additive. Scripts that referenced the former workbench namespace needed to adopt `labkit` or an app entry point. Validation Focused DIC interaction tests, biosignal import tests, layout tests, and the first MATLAB CI workflow were added during this stage. The exact historical command used for each commit was not recorded. Evidence Public-surface cleanup and LabKit rename `9bd8ec8f` through `179885e1`. Unified workbench and file panels `2de7dd0f` through `1be52b9d`. DIC family `aa96ae88` through `fd808a56`. Curvature Measurement `9c1f3798`, `8bcde252`. Biosignal and ECG work `d7c31369` through `b7cabd52`. Initial MATLAB CI `5102640c`. Known limitations and follow-up The new apps exposed interaction problems that ordinary callback tests did not capture well, including popout axes, anchor editing, busy-state reentry, and image zoom ownership. Those issues drove the managed interaction work that followed before v1.0."},{"title":"Launcher adopts the App SDK diagnostic launch contract","url":"history/records/2026/07/LK-20260720-launcher-app-sdk-diagnostics.html","kind":"history","section":"history","keywords":"LK-20260720-launcher-app-sdk-diagnostics 2026-07-20 139 feat compatible labkit_launcher LabKit Core App Framework","text":"Launcher adopts the App SDK diagnostic launch contract id: LK-20260720-launcher-app-sdk-diagnostics date: 2026-07-20 sequence: 139 type: feat compatibility: compatible component: `labkit_launcher` | `1.5.2 -> 1.6.0` scope: LabKit Core scope: App Framework Context The Launcher still passed the retired `RequestAdapter` startup seam after Apps had moved to `labkit.app.Definition`. Normal launch therefore failed before the selected App could create its window. Removing that argument restored startup, but temporarily also removed the user's diagnostic launch path. Decision and rationale Treat the App entrypoint and `Definition.launch` as the only Launcher-to-App runtime boundary. A normal launch uses the SDK defaults. A debug launch passes one typed `labkit.app.diagnostic.Options` value that requests verbose persisted events and the App-owned anonymous synthetic sample. The Launcher continues to read catalog metadata from the single app-owned `definition.m` source without executing the SDK. This preserves its recovery role when an installed framework is incomplete or damaged. Changes Replaced retired runtime-adapter injection with direct App SDK entrypoint calls for normal launch and profiling. Restored **Open Debug** using verbose typed diagnostics and each App's `BuildDebugSample` contract. Added one isolated session folder per debug launch under `artifacts/diagnostics/launcher/`, with the event stream, manifests, and anonymous fixture artifacts. Kept Launcher UI state in a Launcher-owned view record instead of the retired framework registry name. Updated Definition metadata discovery for current name-value syntax while retaining the older literal form for repair-oriented catalog compatibility. Excluded hidden class-folder implementation methods from public API and generated-documentation discovery. User and data impact Existing normal launch, profiling, packaging, update, and documentation actions keep their public behavior. Debug launch now creates explicit diagnostic artifacts and opens the App with its synthetic scenario; it no longer invokes the retired string-mode or request-adapter contracts. Compatibility and migration No additional migration applies beyond the compatibility information in the preceding impact section. Validation Focused Launcher GUI, catalog, progress, profiling, and documentation contracts. App SDK diagnostic integration through DIC Preprocess, including `events.jsonl` and `sample-pack.json` evidence. Documentation source synchronization and public API discovery guardrails. Evidence The validation details above are the supporting evidence for this record. Known limitations and follow-up Developer-led interactive validation should confirm the visible debug launch, the selected App's synthetic state, and the usefulness of the generated diagnostic bundle on the deployment MATLAB version. labkit.app.Definition Compile and launch one immutable App SDK contract. labkit.app.diagnostic.Options Configure one App SDK diagnostic session."},{"title":"Launcher and maintainer tool manuals","url":"history/records/2026/07/LK-20260716-launcher-and-maintainer-manuals.html","kind":"history","section":"history","keywords":"LK-20260716-launcher-and-maintainer-manuals 2026-07-16 63 docs compatible labkit_launcher `docs/apps/labkit-core/launcher/` `docs/development/tools/` `docs/development/maintain-and-release/testing.md`","text":"Launcher and maintainer tool manuals id: LK-20260716-launcher-and-maintainer-manuals date: 2026-07-16 sequence: 63 type: docs compatibility: compatible component: `labkit_launcher` scope: `docs/apps/labkit-core/launcher/` scope: `docs/development/tools/` scope: `docs/development/maintain-and-release/testing.md` Context Launcher behavior was split between Getting Started, architecture notes, source comments, and historical records. Maintainer tools under `tools/` had callable MATLAB entry points but no coherent manual set; profiling details were embedded in the testing command matrix while packaging and codecheck behavior were mostly discoverable only from source. Decision and rationale Document the user-operated launcher beside LabKit Core apps, even though its self-repair implementation remains a root-level standalone file. Document source-checkout tools under Development because they support maintenance rather than app workflows. Keep the existing Testing page as the test-system owner, add a conceptual execution map there, and move profiler call details into the maintainer tool reference. This structure lets readers start from the product they operate or the maintenance task they intend, without mirroring every source directory or mixing tool APIs into reusable `labkit.*` function reference. Changes Added a LabKit Launcher manual covering window actions, programmatic calls, discovery, installation, recovery, tools, limitations, and development milestones. Added a maintainer-tool landing page and detailed references for Code Analyzer reports, app deployment packages, documentation builds, and performance profiling. Added a test-system execution map explaining build tasks, runner discovery, test layers, selectors, plugins, artifacts, and manual-validation boundaries. Connected Getting Started, Apps, LabKit Core, Development, Architecture, Documentation, Testing, Release, the root README, and generated navigation to the new manuals. User and data impact Users can now understand launcher controls and history from the Apps section. Maintainers can copy direct MATLAB calls and inspect every supported option and output without reading tool implementation files. No app workflow, scientific calculation, saved project, input file, or exported result changes. Compatibility and migration This is an additive documentation change. Existing page URLs remain valid. The new launcher and tool pages are generated from Markdown and included in search; no handwritten HTML or third-party documentation package is added. Validation Documentation contracts verify source ownership, generated launcher history, tool entry-point coverage, local links, search indexing, and byte-for-byte agreement between structured sources and the tracked site. Evidence `docs/apps/labkit-core/launcher/README.md` owns the launcher manual. `docs/development/tools/` owns direct maintainer-tool references. `ProjectSurfaceDocumentationTest` protects placement and generated content. Known limitations and follow-up Private app documentation remains in each private repository. Internal private helpers beneath tool folders are intentionally described through their public entry point rather than receiving standalone reference pages."},{"title":"Launcher app version history","url":"history/records/2026/07/LK-20260713-launcher-app-version-history.html","kind":"history","section":"history","keywords":"LK-20260713-launcher-app-version-history 2026-07-13 53 feat compatible labkit_launcher Launcher app version history","text":"Launcher app version history id: LK-20260713-launcher-app-version-history date: 2026-07-13 sequence: 53 type: feat compatibility: compatible component: `labkit_launcher` | `1.3.0 -> 1.4.0` scope: Launcher app version history Context The structured changelog could be parsed by maintainers, but launcher users could not inspect the history of the selected app. Earlier normalization also attached broad release descriptions without recording every app version event, which made histories such as CIC appear to begin years of versions too late. Decision and rationale Expose component-filtered history in the launcher and make exact component events the durable lookup key. A user should be able to move from the current app catalog directly to its evolution record without reading Git history or understanding changelog internals. Changes Added `labkit_launcher(\"history\", appCommand)` for programmatic history lookup and a Version History viewer for the selected launcher app. Added explicit component introduction events and reconstructed every tracked launcher, facade, and app version transition from `origin/main` history. Added continuous-history validation so missing introductions, gaps, and current-version mismatches fail the release guardrail. User and data impact Launcher users can inspect dated version transitions, compatibility, rationale, impact, and evidence for the selected app. App calculations and user data are unchanged. Compatibility and migration The launcher command and button are additive. Existing list, version, package, maintenance, and app-launch workflows remain available. Validation `LauncherGuiTest` covers programmatic filtering and the hidden GUI viewer; `ChangelogGuardrailTest` validates complete version chains against current metadata. These checks were included in the combined mainline change `4a6c41dd`. Evidence Component history, launcher viewer, and changelog validation were included in `4a6c41dd`. Historical component events were reconstructed from version-file changes on the then-current `origin/main` history. Known limitations and follow-up History begins when version metadata was first tracked for each component. Behavior before that point can only be inferred from older source commits and is not assigned invented version numbers."},{"title":"Launcher code-analysis export","url":"history/records/2026/07/LK-20260701-launcher-code-analysis-export.html","kind":"history","section":"history","keywords":"LK-20260701-launcher-code-analysis-export 2026-07-01 29 feat compatible labkit_launcher Launcher code-analysis export","text":"Launcher code-analysis export id: LK-20260701-launcher-code-analysis-export date: 2026-07-01 sequence: 29 type: feat compatibility: compatible component: `labkit_launcher` | `1.1.6 -> 1.2.0` scope: Launcher code-analysis export Context The launcher offered a Code Analyzer action, but its earlier implementation carried substantial custom export code. That made a maintenance tool harder to maintain than the MATLAB analysis it was exposing. Decision and rationale Use MATLAB's native issue representation and export path, and keep the launcher responsible only for choosing the target and destination. This reduced custom conversion logic while preserving a launcher-level entry point for the report. Changes `labkit_launcher` `1.1.6 -> 1.2.0` Exported launcher Code Analyzer issues natively. User and data impact The launcher could export Code Analyzer findings in a MATLAB-supported form without requiring a separate script. This action inspected source code only and did not start or modify an app project. Compatibility and migration Existing launcher actions remained available. Newly exported issue files used MATLAB's native representation rather than the removed custom conversion. Validation `LauncherGuiTest` gained coverage for the native issue-export path and the implementation in `8fd3ddff` removed more launcher code than it added. Evidence Main commit `8fd3ddff`. Known limitations and follow-up Code analysis remained a maintainer tool. It did not become a prerequisite for launching an app or a replacement for the repository's automated checks."},{"title":"Launcher manager and stale callback fix","url":"history/records/2026/06/LK-20260626-launcher-manager-and-stale-callback-fix.html","kind":"history","section":"history","keywords":"LK-20260626-launcher-manager-and-stale-callback-fix 2026-06-26 13 fix compatible labkit_launcher labkit_launcher labkit.ui Launcher manager and stale callback fix","text":"Launcher manager and stale callback fix id: LK-20260626-launcher-manager-and-stale-callback-fix date: 2026-06-26 sequence: 13 type: fix compatibility: compatible component: `labkit_launcher` | `1.0.0 -> 1.1.0` component: `labkit_launcher` | `1.1.0 -> 1.1.1` component: `labkit.ui` | `3.0.0 -> 3.0.1` scope: Launcher manager and stale callback fix Context The launcher could update LabKit but did not offer an explicit choice among a recent release, a tag, and the main branch. Separately, image drag tools could leave old callbacks attached after an interaction ended. Decision and rationale Add a managed version selector backed by an install manifest, and make image interaction cleanup restore or release every temporary callback. Both changes reduce hidden state that otherwise survives beyond the user's selected action. Changes `labkit_launcher` `1.0.0 -> 1.1.1` `labkit.ui` `3.0.0 -> 3.0.1` Added the launcher version manager and managed-manifest requirement. Released stale image drag callbacks. User and data impact Users could deliberately install a supported release or development revision. Ending an image drag no longer left the figure responding to an obsolete tool. Saved app data did not change. Compatibility and migration Existing launcher installations remained usable. Managed installations needed the launcher manifest for version replacement; image editors required no saved- data conversion after their stale callbacks were released. Validation The listed commits added launcher-manager/manifest coverage and regression checks for image callback cleanup. Exact historical commands were not recorded. Evidence Main commits `fe8654c9`, `ef89cf77`, and `3d23b7f1`. Known limitations and follow-up Version selection still depended on network access for remote revisions; already installed local versions remained usable offline."},{"title":"Launcher reads the single App definition","url":"history/records/2026/07/LK-20260716-launcher-definition-metadata.html","kind":"history","section":"history","keywords":"LK-20260716-launcher-definition-metadata 2026-07-16 78 refactor compatible labkit_launcher App discovery Product metadata ownership","text":"Launcher reads the single App definition id: LK-20260716-launcher-definition-metadata date: 2026-07-16 sequence: 78 type: refactor compatibility: compatible component: `labkit_launcher` | `1.5.0 -> 1.5.1` scope: App discovery scope: Product metadata ownership Context The launcher discovered entrypoints independently from App runtime creation, but obtained versions by parsing a separate package `version.m`. That kept the old metadata file alive even after Runtime V2 gained a single definition contract. Decision and rationale Keep discovery lightweight and self-contained while changing its source of truth. The launcher now reads `AppVersion` and `Updated` literals from the App's `definition.m`; it does not execute the definition or start the App. Changes Preferred `definition.m` product metadata during public and private App discovery. Added a synthetic private-App catalog test with no `version.m` file. Retained a documented internal fallback only for Apps awaiting migration. User and data impact Launcher catalogs continue to show version and update dates. A migrated App does not need a second metadata file solely for discovery. Compatibility and migration The change is compatible. Existing Apps remain discoverable through the temporary fallback; migrated Apps use only their definition. The fallback is removed after the last App migration. Validation The launcher catalog test creates an isolated App definition, points private discovery at it, and verifies the returned version and date without a `version.m` file. Evidence [LabKit Launcher](../../../../apps/labkit-core/launcher/README.md) explains definition-backed discovery. [Runtime and Lifecycle](../../../../framework/guides/runtime.md) defines the App product metadata fields. Known limitations and follow-up P-code packaging metadata will be audited with the deployment workflow before the transitional parser fallback is removed."},{"title":"Launcher update reliability","url":"history/records/2026/07/LK-20260701-launcher-update-reliability.html","kind":"history","section":"history","keywords":"LK-20260701-launcher-update-reliability 2026-07-01 25 fix compatible labkit_launcher labkit_launcher Launcher update reliability","text":"Launcher update reliability id: LK-20260701-launcher-update-reliability date: 2026-07-01 sequence: 25 type: fix compatibility: compatible component: `labkit_launcher` | `1.1.3 -> 1.1.4` component: `labkit_launcher` | `1.1.4 -> 1.1.5` scope: Launcher update reliability Context The self-contained launcher could install a ZIP release, but the replacement path performed more filesystem work than necessary and duplicated logic for locating, unpacking, and replacing the workbench. Slow replacement made a successful update look stalled; duplicated recovery paths made failures harder to reason about. Decision and rationale Minimize the files touched during an update and give ZIP replacement one straight-line implementation. Preserve the existing installation until the download and unpack steps have produced a usable replacement. Changes `labkit_launcher` `1.1.3 -> 1.1.5` Sped up launcher zip updates. Simplified launcher zip replacement. User and data impact ZIP updates completed with less waiting and fewer intermediate operations. A failure before replacement left the existing checkout available, while a successful update continued to present the same launcher entry point. Compatibility and migration Existing managed installations remained updateable. The replacement algorithm changed internally and did not require users to reinstall a working checkout. Validation Both commits extended `LauncherGuiTest` around download, replacement, and recovery behavior. The exact historical commands were not recorded. Evidence Main commits `ebf86cf2` and `becf9391`. Known limitations and follow-up The updater still depended on the release artifact being trustworthy. Later release work added stronger tag-to-asset verification and update diagnostics."},{"title":"Legacy import and first app workbench","url":"history/records/2026/05/LK-20260528-initial-app-workbench-foundation.html","kind":"history","section":"history","keywords":"LK-20260528-initial-app-workbench-foundation 2026-05-28 1 feat compatible historical project evolution","text":"Legacy import and first app workbench id: LK-20260528-initial-app-workbench-foundation date: 2026-05-28 sequence: 1 type: feat compatibility: compatible scope: historical project evolution Context LabKit began with a direct import of older MATLAB analysis and GUI code. The electrochem workflows mixed file parsing, calculations, session state, plots, and exports inside large entry scripts, and several root commands exposed the same legacy implementation through different paths. Decision and rationale Separate the imported code by responsibility before adding new features. Move Gamry parsing and pulse detection into reusable DTA operations; keep CIC, CSC, VT resistance, EIS, and chrono calculations with their workflows; then expose each workflow through one package-backed app command. Extract shared UI pieces only after the app behavior is visible in more than one workflow. Changes Imported the legacy MATLAB tree without rewriting its scientific formulas. Extracted chrono, EIS, and CV/CT DTA parsers plus pulse detection and named synthetic fixtures. Separated chrono alignment/export, CIC, CSC, VT resistance, and EIS result operations from their GUI assembly. Added named app entry points and package-backed runners, then removed the duplicate root legacy entry points and legacy GUI directory. Introduced the first shared two-pane/tabbed shells, file panels, plot controls, log panels, and axes helpers used by the electrochem apps. User and data impact Users gained named electrochem app commands instead of opening the old GUI scripts directly. Calculations and exported values were intended to remain unchanged while code ownership moved; laboratory files remained external inputs rather than being copied into a central LabKit database. Compatibility and migration Component/app version files did not exist yet. Old root GUI entry points were removed as package-backed app commands became the supported launch path. Validation The first regression evidence included named DTA fixtures, calculation tests, an optional GUI smoke runner, and GUI compatibility checks. A single standard test command had not yet been established. Evidence Initial import `5973bde0`. Parser and calculation extraction from `fc70f9b2` through `9f7c6e4e`. App entrypoint and package migration from `40f46561` through `4d58066c`. First shared app-shell work from `f05f4a35` through `61a8cb87`. Known limitations and follow-up This stage improved structure but still contained several broad shared UI helpers and session abstractions that were narrowed during the following DTA facade and app-boundary work."},{"title":"Legacy import preserves portable references without exposing their schema","url":"history/records/2026/07/LK-20260716-opaque-source-import.html","kind":"history","section":"history","keywords":"LK-20260716-opaque-source-import 2026-07-16 102 feat compatible labkit.ui App Framework Project portability","text":"Legacy import preserves portable references without exposing their schema id: LK-20260716-opaque-source-import date: 2026-07-16 sequence: 102 type: feat compatibility: compatible component: `labkit.ui` | `7.4.2 -> 7.4.3` scope: App Framework scope: Project portability Context The GUI-free source-record factory accepted filepaths, but an App importing an older MAT variable could already receive a portable reference containing the only usable relative location. Recreating the record from its original path would discard that portability; preserving it required the importer to copy the Runtime's private nested reference schema. Decision and rationale Keep one public source factory and allow its source value to be either a normal filepath or an existing portable reference passed as one opaque struct. The Runtime validates and canonicalizes the latter. Apps still never construct or read nested reference fields. Changes Extended `labkit.ui.runtime.sourceRecord` with an opaque-reference overload. Added strict validation for the supported portable-reference schema, scalar text fields, filename, and usable relative or original path. Canonicalized imported references so unrelated legacy fields do not enter a current project. Documented the distinction between normal filepath creation and legacy reference preservation. User and data impact Moved legacy projects retain their relative source fallback during upgrade. App importers no longer need to duplicate Runtime serialization fields or choose between architectural ownership and data portability. Compatibility and migration Existing filepath calls and injected source-record services are unchanged. The overload accepts only the current supported reference schema; malformed or newer references fail before they can enter a project. Validation Focused Runtime tests cover normal path creation, opaque-reference canonicalization, relative-path preservation, missing fields, unsupported schema versions, source path access, and the public package surface. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Framework](../../../../framework/README.md) [Architecture](../../../../development/build-apps/architecture.md) Known limitations and follow-up Opaque-reference import is intended for trusted project importers, not as a general App-defined serialization extension. Video Marker is the first legacy importer scheduled to consume the overload."},{"title":"Local validation uses one focused route and CI owns full coverage","url":"history/records/2026/07/LK-20260721-local-validation-routing.html","kind":"history","section":"history","keywords":"LK-20260721-local-validation-routing 2026-07-21 150 test compatible Test routing Continuous Integration","text":"Local validation uses one focused route and CI owns full coverage id: LK-20260721-local-validation-routing date: 2026-07-21 sequence: 150 type: test compatibility: compatible scope: Test routing scope: Continuous Integration Context The repository exposed both `changedFast` and a conservative `changed` task. For documentation, agent guidance, and CI workflow changes they selected the same complete project suite, so running both locally duplicated work that the cross-platform CI already repeated more comprehensively. Decision and rationale Keep one local changed-file task, `changedFast`, for a focused pre-push check. PR and main-push CI remain the complete validation gate because they run the full headless and hidden-GUI suites on every supported platform. Changes Removed the public conservative `changed` task and its runner entry. Guidance, templates, workflows, and CI helpers now route to their owning documentation or CI guardrails instead of the complete project suite. Broad GUI candidate selection remains reduced to representative workflows for the local route. User and data impact App behavior, saved projects, analysis results, and laboratory data do not change. Contributors receive faster local feedback while the same complete platform coverage remains mandatory before delivery. Compatibility and migration Use `buildtool changedFast` for the local pre-push checkpoint. The retired `buildtool changed` command is intentionally unavailable; use CI results for complete validation rather than substituting another local broad run. Validation Build-task catalog and route-contract tests verify the single public local route and its owner-specific selections. The changed-file gate exercises the selected guardrails, while CI continues to run full headless and hidden-GUI coverage. Evidence The CI workflow invokes `headless` and `gui` on Linux, macOS, and Windows. The validation planner records a reason for every selected local guardrail. Known limitations and follow-up Local `changedFast` is intentionally not a substitute for CI or manual App review. If a new shared surface lacks an owning test route, add that route rather than broadening unrelated local checks."},{"title":"MATLAB-compatible image conversion API","url":"history/records/2026/07/LK-20260713-matlab-compatible-image-conversion.html","kind":"history","section":"history","keywords":"LK-20260713-matlab-compatible-image-conversion 2026-07-13 47 refactor breaking labkit.image labkit_DICPostprocess_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app MATLAB-compatible image conversion API","text":"MATLAB-compatible image conversion API id: LK-20260713-matlab-compatible-image-conversion date: 2026-07-13 sequence: 47 type: refactor compatibility: breaking component: `labkit.image` | `1.2.0 -> 2.0.0` component: `labkit_DICPostprocess_app` | `1.3.5 -> 1.3.6` component: `labkit_BatchImageCrop_app` | `1.6.7 -> 1.6.8` component: `labkit_CurvatureMeasurement_app` | `1.3.4 -> 1.3.5` component: `labkit_FocusStack_app` | `1.4.8 -> 1.4.9` component: `labkit_ImageEnhance_app` | `1.5.7 -> 1.5.8` component: `labkit_ImageMatch_app` | `1.5.7 -> 1.5.8` scope: MATLAB-compatible image conversion API Context The `toDouble`, `toLuma`, and `toRgbDouble` names combined class conversion, channel shaping, and clipping in ways that differed from familiar MATLAB APIs. Decision and rationale Use MATLAB-compatible names and call contracts for replacement functions, and keep orthogonal RGB shaping explicit so users do not need to learn a composite LabKit normalization rule. Changes Added base-MATLAB `labkit.image.im2double` and `labkit.image.rgb2gray`. Kept channel shaping in `ensureRgb` and made clipping explicit at call sites. Removed the ambiguous conversion helpers and centralized Rec.601 ownership. User and data impact Base-MATLAB users receive familiar image conversion behavior without hidden toolbox requirements. Existing app image results retain their intended ranges and channel shapes through explicit pipelines. Compatibility and migration This is a breaking facade rename. External callers replace removed helper names with `im2double`, `rgb2gray`, and `ensureRgb` as separately needed. Validation Image facade, downstream app, toolbox-shadow, and base-MATLAB ownership tests cover class conversion, luma values, and representative workflows. Evidence The current API contracts are documented in the [Image Library](../../../../libraries/image/README.md). Commit `e3f71c2d` aligned the conversion functions with MATLAB call behavior. Known limitations and follow-up The compatibility layer intentionally covers the LabKit-used MATLAB contracts, not every Image Processing Toolbox function. labkit.image.im2double Convert image data to double using MATLAB's im2double contract. labkit.image.rgb2gray Convert RGB data using MATLAB's rgb2gray call contract."},{"title":"Managed image interactions and diagnostic tracing","url":"history/records/2026/06/LK-20260604-managed-image-interactions.html","kind":"history","section":"history","keywords":"LK-20260604-managed-image-interactions 2026-06-04 4 feat compatible historical project evolution","text":"Managed image interactions and diagnostic tracing id: LK-20260604-managed-image-interactions date: 2026-06-04 sequence: 4 type: feat compatibility: compatible scope: historical project evolution Context Image and ECG apps had made the workbench broader, but they also revealed a class of GUI failures that did not appear in parser or calculation tests. An anchor editor could re-enter a callback, a scale bar could lose ownership, an axes popout could stop reflecting the source, and a long operation could leave controls in an ambiguous state. Decision and rationale Move repeatable interaction mechanics into the UI foundation while leaving image-specific geometry and workflow state in each app. Give long-running actions an explicit busy-state guard, make image axes and tools managed resources, and record callback progress in diagnostic traces that could be inspected after a failure. Changes Added axes popout support and corrected image aspect and menu refresh behavior. Added shared UI control helpers and a reusable ECG peak detector facade. Added the Focus Stack app with automatic and manual image selection. Improved anchor insertion, curvature controls, and scale-bar ownership. Added a busy-state guard to prevent overlapping actions. Introduced a managed image-axes runtime, layered UI facades, and app debug trace logging. Split large app entry points into app-owned private workflow helpers rather than widening the public framework API. User and data impact Users gained Focus Stack and more predictable image editing. Popout views, anchors, scale bars, and long operations provided clearer feedback and were less likely to leave an app in a broken intermediate state. Debug traces made it possible to distinguish a slow or failed callback from an unresponsive window. The changes affected UI state and presentation; they did not intentionally alter existing scientific results. Compatibility and migration Apps gradually moved from direct axes and interaction setup to the managed UI facades. App-private geometry helpers remained private, so the framework did not promise a public API for every interaction detail. Validation The period added public API option documentation, app-private helper tests, interaction regression coverage, and focused checks for UI layout ownership. No single historical validation command covers the complete stage. Evidence Axes popout and control helpers `1e9022c4` through `2136009f`. ECG detector and filtering work `e8450652` through `adb7dfbf`. Focus Stack `08518e91`, `cc4cdf92`. Busy guard `ac36bd54`. Image interaction and scale-bar work `f58b8559` through `5304fa20`. Managed axes, traces, and layered UI facades `27bdbdd8`, `e86e4ea3`, `da0663f1`, `c4cae633`. Known limitations and follow-up The interaction layer was still evolving and the test infrastructure mixed custom runners with newer MATLAB tests. The v1.0 stabilization pass addressed test entry points, package ownership, and remaining compatibility aliases."},{"title":"Managed scientific and conversion constants","url":"history/records/2026/07/LK-20260713-managed-calculation-constants.html","kind":"history","section":"history","keywords":"LK-20260713-managed-calculation-constants 2026-07-13 48 refactor compatible labkit.dta labkit.rhs labkit.biosignal labkit_ChronoOverlay_app labkit_CSC_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app Managed scientific and conversion constants","text":"Managed scientific and conversion constants id: LK-20260713-managed-calculation-constants date: 2026-07-13 sequence: 48 type: refactor compatibility: compatible component: `labkit.dta` | `2.0.0 -> 2.0.1` component: `labkit.rhs` | `1.0.0 -> 1.0.1` component: `labkit.biosignal` | `1.0.0 -> 1.0.1` component: `labkit_ChronoOverlay_app` | `1.3.5 -> 1.3.6` component: `labkit_CSC_app` | `1.3.9 -> 1.3.10` component: `labkit_NerveResponseAnalysis_app` | `1.3.4 -> 1.3.5` component: `labkit_ResponseReviewStats_app` | `1.3.4 -> 1.3.5` scope: Managed scientific and conversion constants Context Scientific coefficients, device-format gains, unit conversions, and numeric tolerances were sometimes left as unexplained literals or repeated across callers, making origin and change impact difficult to audit. Decision and rationale Give each semantic calculation constant one named owner and a nearby source or purpose comment, while exempting ordinary indices and explicit UI geometry that do not encode scientific meaning. Changes Named and documented Rec.601, sRGB/CIE, DTA/RHS gains, SI conversions, tolerances, and empirical policies across facades and apps. Centralized repeated CSC charge-density, CIC display-unit, and curvature tolerance contracts. Added repository-wide magic-number and rectangle-interaction guardrails. User and data impact Calculation results are preserved, but future changes now expose the constant's meaning and provenance instead of silently editing an unexplained literal. Compatibility and migration No user migration is required. Public function call contracts and output schemas are unchanged by this record. Validation `MagicNumberGovernanceTest`, rectangle governance, module compatibility tests, and affected app tests cover centralized ownership and preserved numeric behavior. Evidence Source comments use the `Constant:` marker and guardrail diagnostics name the unmanaged file and line. Commit `125338c0` introduced the calculation-constant checks and the corresponding source annotations. Known limitations and follow-up The scanner targets semantically suspicious precision and notation; review is still required for simple integers or short decimals whose meaning is hidden."},{"title":"Migration helper cleanup","url":"history/records/2026/06/LK-20260630-migration-helper-cleanup.html","kind":"history","section":"history","keywords":"LK-20260630-migration-helper-cleanup 2026-06-30 23 refactor compatible labkit.ui labkit_DICPostprocess_app labkit_BatchImageCrop_app labkit_BatchImageCrop_app labkit_ImageEnhance_app labkit_RHSPreview_app labkit_RHSPreview_app historical project evolution","text":"Migration helper cleanup id: LK-20260630-migration-helper-cleanup date: 2026-06-30 sequence: 23 type: refactor compatibility: compatible component: `labkit.ui` | `3.2.8 -> 3.2.9` component: `labkit_DICPostprocess_app` | `1.2.3 -> 1.2.4` component: `labkit_BatchImageCrop_app` | `1.3.7 -> 1.3.8` component: `labkit_BatchImageCrop_app` | `1.3.8 -> 1.3.9` component: `labkit_ImageEnhance_app` | `1.3.4 -> 1.3.5` component: `labkit_RHSPreview_app` | `1.2.2 -> 1.2.3` component: `labkit_RHSPreview_app` | `1.2.3 -> 1.2.4` scope: historical project evolution Context Several apps still split one small decision across multiple temporary helper files created during earlier package migrations. That made simple state and preview behavior harder to follow without creating a reusable API. Decision and rationale Consolidate related values behind one clearly named operation and delete pass-through helpers whose only purpose was reducing file length. Preserve the visible app behavior while making each calculation or state summary traceable from its caller. Changes DIC Post, Batch Crop, and RHS Preview patch bumped. Retired migration helper debt. Consolidated RHS preview window bounds, Batch Crop scale state, and Image Enhance export helpers. User and data impact No workflow or result format changed. The cleanup reduced internal indirection in Image Enhance export, Batch Crop scale summaries, RHS Preview window bounds, and a small set of DIC/electrochem helpers. Compatibility and migration The consolidated helpers preserved the app-facing state and result structures. No project or export format changed as the duplicate implementations were removed. Validation Commits `7f73b71b`, `e3349af6`, `733fb951`, `98a2b02c`, and `391540a7` added or updated focused tests for each consolidated operation. Evidence Main commits `7f73b71b`, `e3349af6`, `733fb951`, `98a2b02c`, and `391540a7`. Known limitations and follow-up This was a behavior-preserving cleanup. Later workflow-first packages replaced some of the package names shown in the historical commits."},{"title":"Minimal App contract and current authoring manuals","url":"history/records/2026/07/LK-20260716-minimal-app-contract.html","kind":"history","section":"history","keywords":"LK-20260716-minimal-app-contract 2026-07-16 115 docs compatible labkit-project App authoring Runtime V2 contract guardrails","text":"Minimal App contract and current authoring manuals id: LK-20260716-minimal-app-contract date: 2026-07-16 sequence: 115 type: docs compatibility: compatible component: `labkit-project` scope: App authoring scope: Runtime V2 contract guardrails Context Runtime V2 already supplied default project, session, action, presenter, and startup capabilities, but the complete-App tutorial and several current manuals still taught the retired split metadata and generic lifecycle package shape. The App structure guardrail also prohibited those files only when an App already owned `projectSpec.m`, leaving static Apps unprotected. Decision and rationale Make progressive capability the documented and tested authoring contract. A static App consists of a thin entrypoint, one definition, and one data-only layout. Actions, presentation, durable project state, transient reconstruction, and startup are added independently only when the product needs them. Changes Rewrote the complete-App tutorial around the three-file starting point and one `projectSpec.m` create/validate/migrate entry. Updated architecture, framework, private-App, library, testing, release, and history manuals plus scoped App rules and the App-builder skill to use definition-owned metadata and progressive optional capabilities. Added a hidden-GUI launch test whose definition omits every optional Runtime V2 component. Corrected the tutorial's numeric field declaration after the real launch test exposed its implicit text-control mismatch. Made the App package guardrail reject retired metadata, lifecycle, state, startup, and per-version migration files for every App shape. User and data impact App behavior and scientific results do not change. A developer can begin with three source files and add each larger architectural concept only when a real workflow requires it. Public and private App documentation now teach the same contract. Compatibility and migration This change documents and protects the already migrated Runtime V2 structure. It does not alter saved project payloads or remove the temporary low-level legacy project-migration reader used by framework tests. Validation Focused contract and GUI tests cover both the forbidden retired structures and an actual launch from the minimal definition. A documentation contract checks the tutorial, scoped App rules, and App-builder skill together. Documentation consistency checks and a regenerated site validate navigation and history metadata. Evidence [Build a Complete App](../../../../development/build-apps/complete-app.md) gives the progressive file-by-file tutorial. [Architecture](../../../../development/build-apps/architecture.md) defines the current package shape and ownership boundaries. [Runtime and Lifecycle](../../../../framework/guides/runtime.md) specifies every optional component and callback. Known limitations and follow-up The minimal contract proves framework defaults, not that every complex App has already reached its lowest maintainable complexity. App-by-App workflow and framework-boundary audits continue separately."},{"title":"Minimal App definitions","url":"history/records/2026/07/LK-20260716-minimal-app-definition.html","kind":"history","section":"history","keywords":"LK-20260716-minimal-app-definition 2026-07-16 76 feat compatible labkit.ui App authoring Runtime V2 definition defaults","text":"Minimal App definitions id: LK-20260716-minimal-app-definition date: 2026-07-16 sequence: 76 type: feat compatibility: compatible component: `labkit.ui` | `7.0.0 -> 7.1.0` scope: App authoring scope: Runtime V2 definition defaults Context Runtime V2 already normalized missing project and session buckets, but every definition still had to provide project create/validate callbacks, at least one action, and a presenter. A static App therefore needed lifecycle files and placeholder functions that owned no behavior. Decision and rationale Make lifecycle components proportional to product behavior. Every App still declares a stable ID, title, and semantic layout. The framework supplies empty canonical state and no-op dynamic behavior until the App opts into durable data, transient cache, actions, or presentation. Changes Made `Project`, `Actions`, and `Present` optional in `labkit.ui.runtime.define`; `CreateSession` was already optional. Added a framework-owned version-1 empty project specification and empty presenter model. Allowed an empty action registry when no layout event or startup phase references an action. Added a GUI contract test that launches a definition containing only `Id`, `Title`, and `Layout` and verifies both canonical state roots. Rewrote App-development entry guidance around capability tiers instead of a fixed list of placeholder files. User and data impact Existing Apps behave unchanged. A new static App does not need `createProject.m`, `createSession.m`, `validateProject.m`, `definitionActions.m`, or a presenter. Those components are introduced only when the App gains corresponding behavior. Compatibility and migration The change is additive within UI 7. Existing complete definitions remain valid. Saved project and source schemas do not change. Validation The minimal-definition GUI test exercises real launch, canonical project and session creation, layout construction, empty presentation, and readiness. Definition validation and public documentation guardrails cover both minimal and full definitions. Evidence [App Framework](../../../../framework/README.md) introduces the minimal definition. [Runtime and Lifecycle](../../../../framework/guides/runtime.md) lists required and optional definition components. [App Development](../../../../development/build-apps/app-development.md) maps files to capabilities instead of treating them as universal boilerplate. Known limitations and follow-up Apps that own a project schema still use explicit project specification. The next lifecycle cleanup consolidates each App's project factory, validator, and ordered migration steps behind one `projectSpec.m` entry point rather than scattered version-step files."},{"title":"Multi-app launcher packages","url":"history/records/2026/07/LK-20260709-multi-app-launcher-packages.html","kind":"history","section":"history","keywords":"LK-20260709-multi-app-launcher-packages 2026-07-09 42 feat compatible labkit_launcher Multi-app launcher packages","text":"Multi-app launcher packages id: LK-20260709-multi-app-launcher-packages date: 2026-07-09 sequence: 42 type: feat compatibility: compatible component: `labkit_launcher` | `1.2.7 -> 1.3.0` scope: Multi-app launcher packages Context The deployment tool could package one app, but laboratory workflows often used a small related set. Creating one ZIP per app duplicated the shared LabKit runtime, while manually merging ZIP files risked inconsistent entry files and manifests. The launcher's selected row also could not double as a multi-select without making Open and Debug ambiguous. Decision and rationale Add a separate Package checkbox to each launcher row. Keep the ordinary row selection for Open and Debug, and let checked rows produce one bundle with one entry file per app and a manifest describing the complete package. Changes `labkit_launcher` `1.2.7 -> 1.3.0` Project deployment tooling, multi-app bundle support. Added an independent `Package` checkbox column to the launcher app table so users can choose multiple apps without changing the row selected for Open or Debug. `Package Checked` and `Checked P-code` now create one zip containing every checked app, one direct entry file per app, and a multi-app manifest. Kept single-app package names, result fields, and manifest schema compatible when only one app is supplied to `packageLabKitApp`. User and data impact Users could distribute a related group of apps in one source or P-code ZIP without including the rest of the workbench. Opening and debugging still acted on the highlighted app, so preparing a package did not change normal launcher navigation. Compatibility and migration Existing direct calls that package one app continue to produce the original single-app package contract. Validation The commit expanded deployment unit tests, launcher packaging GUI coverage, selection helpers, changed-file routing, and build-task efficiency checks. The exact historical command was not recorded. Evidence Mainline commit `8a23a52`. Known limitations and follow-up Bundles intentionally included selected apps and their LabKit dependencies, not tests, full documentation, or unrelated private workspaces. P-code packages still required a compatible MATLAB runtime."},{"title":"Nerve Response Analysis uses fixed source identities","url":"history/records/2026/07/LK-20260716-nerve-response-structure.html","kind":"history","section":"history","keywords":"LK-20260716-nerve-response-structure 2026-07-16 107 refactor compatible labkit_NerveResponseAnalysis_app Neurophysiology App structure","text":"Nerve Response Analysis uses fixed source identities id: LK-20260716-nerve-response-structure date: 2026-07-16 sequence: 107 type: refactor compatibility: compatible component: `labkit_NerveResponseAnalysis_app` | `1.4.2 -> 1.4.3` scope: Neurophysiology scope: App structure Context Nerve Response Analysis split one project schema across generic lifecycle files and kept two additional lifecycle helpers to filter and replace source records by role. Product metadata remained in separate requirement/version functions, while session and presentation code read nested portable-reference fields directly. Decision and rationale Use `filterRecord` and `protocol` as the two stable App-owned source IDs and matching roles. Runtime V2 already supports semantic path lookup by ID and an injected upsert service, so role-filter wrappers duplicate framework behavior without adding scientific meaning. Keep event detection, recording analysis, CAP measurement, presentation, and result writing in their existing concrete workflow packages. Changes Consolidated command identity, display metadata, version, requirements, project, session, layout, actions, presenter, renderer, and debug capability through the single definition. Concentrated project creation, validation, and the version-1 source upgrade in `projectSpec` behind one `Migrate` callback. Moved parsed JSON and transient workflow reconstruction to root `createSession`. Replaced App-owned role filtering/replacement helpers with `sourcePaths` and the injected `upsertSource` service. Strengthened validation so the two source IDs are unique, supported, and match their declared roles. Removed the generic lifecycle package and separate requirement/version files. User and data impact Filter/protocol selection, run limits, event and train detection, CAP metrics, issue handling, previews, output-folder defaults, JSON export, manifest output, reset, and project reopening are unchanged. The App version advances to 1.4.3; durable payload version remains 2. Compatibility and migration Version-1 projects still combine their separate filter and protocol records into the canonical source collection. Runtime V2 invokes the single migration entry and owns iteration. Current version-2 files already written with the documented fixed IDs load without data transformation. Validation Focused unit tests cover migration, source identity validation, event trains, differential/common-mode calculations, CAP metrics, filter labels, and the legacy keep-column input. The hidden GUI workflow covers filter selection, analysis, counts/issues presentation, JSON and manifest export, project save, reset, reopen, and reanalysis. Evidence [Nerve Response Analysis](../../../../apps/neurophysiology/nerve-response-analysis/README.md) [RHS Preview](../../../../apps/neurophysiology/rhs-preview/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Automated tests do not establish that a selected protocol, stimulation source, or timing window is physiologically correct. RHS Preview still uses the older split lifecycle structure and requires its own independent convergence review."},{"title":"One project migration entry per App","url":"history/records/2026/07/LK-20260716-single-project-migration-entry.html","kind":"history","section":"history","keywords":"LK-20260716-single-project-migration-entry 2026-07-16 81 feat compatible labkit.ui Runtime V2 projects App authoring","text":"One project migration entry per App id: LK-20260716-single-project-migration-entry date: 2026-07-16 sequence: 81 type: feat compatibility: compatible component: `labkit.ui` | `7.2.1 -> 7.3.0` scope: Runtime V2 projects scope: App authoring Context Runtime V2 already applied project migrations sequentially, but each App had to expose a cell array containing every historical version-step function. Schema growth therefore increased files and wiring even though the framework owned the actual migration loop. Decision and rationale Give each persistent App one migration entry. `Migrate(project,fromVersion)` upgrades exactly one step; Runtime V2 supplies each missing version in order, validates every intermediate payload, and continues to the current version. Changes Added the scalar `Project.Migrate` callback. Kept per-step serialization validation, newer-version rejection, atomic load behavior, final project validation, session rebuild, and dirty upgrade state unchanged. Converted the framework's version-1-to-3 round-trip fixture to one callback with two version cases. Retained `Project.Migrations` only as a temporary bridge for existing Apps. User and data impact Saved projects behave as before. App maintainers can keep create, validate, and every schema transition as local functions in one `projectSpec.m` instead of maintaining a growing migration-file registry. Compatibility and migration The contract is additive within UI 7. Existing Apps continue to load during family-sized migration. An App must not declare both migration forms. Validation The Runtime V2 project test opens a version-1 payload in a version-3 App, executes both steps through one callback, verifies final data and source relinking, saves the current payload version, and checks failure atomicity. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) documents the project declaration and loop. [App Development](../../../../development/build-apps/app-development.md) describes the single project file. Known limitations and follow-up Existing Apps still need their lifecycle functions consolidated into `projectSpec.m`. The legacy migration-array bridge will be removed after the last family is migrated."},{"title":"Output folder prompts","url":"history/records/2026/06/LK-20260630-output-folder-prompts.html","kind":"history","section":"history","keywords":"LK-20260630-output-folder-prompts 2026-06-30 20 feat compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_BatchImageCrop_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app Output folder prompts","text":"Output folder prompts id: LK-20260630-output-folder-prompts date: 2026-06-30 sequence: 20 type: feat compatibility: compatible component: `labkit.ui` | `3.2.5 -> 3.2.6` component: `labkit_DICPostprocess_app` | `1.2.0 -> 1.2.1` component: `labkit_DICPreprocess_app` | `1.2.0 -> 1.2.1` component: `labkit_BatchImageCrop_app` | `1.3.3 -> 1.3.4` component: `labkit_FocusStack_app` | `1.2.1 -> 1.2.2` component: `labkit_ImageEnhance_app` | `1.3.1 -> 1.3.2` component: `labkit_ImageMatch_app` | `1.3.1 -> 1.3.2` component: `labkit_NerveResponseAnalysis_app` | `1.2.1 -> 1.2.3` component: `labkit_ResponseReviewStats_app` | `1.2.1 -> 1.2.2` scope: Output folder prompts Context Exporting from different apps opened `uigetdir` directly, chose starting folders differently, and could not substitute a noninteractive chooser in a test. The repeated dialog code also made cancellation handling inconsistent. Decision and rationale Provide one output-folder prompt that selects a safe default, returns an explicit cancellation flag, remembers a successful folder, and accepts an injected chooser for tests. Apps would still decide when an output folder was needed and what they wrote there. Changes `labkit.ui` `3.2.5 -> 3.2.6` DIC apps, Batch Crop, Focus Stack, Image Enhance/Match, Nerve Response, and Response Review patch bumped. Added `promptOutputFolder`. Migrated output-folder prompts with chooser injection and safe defaults. User and data impact Output dialogs began in a useful folder and cancellation returned cleanly to the app. The selected folder was remembered as a preference; no output was created until the owning app performed its export. Compatibility and migration Existing output locations and exported file formats remained valid. Apps moved from direct folder dialogs to the shared prompt without changing what they wrote after selection. Validation Commit `c5055b98` added `AppHookHelpersTest` coverage for defaults, cancellation, successful selection, and chooser injection, then updated the affected app compatibility checks. Evidence Main commit `c5055b98`. Known limitations and follow-up Runtime V2 later moved dialog access into injected services, preserving the same separation between app decisions and platform dialog mechanics."},{"title":"Owner-minimal validation routing compiles canonical test groups","url":"history/records/2026/07/LK-20260722-owner-minimal-validation-routing.html","kind":"history","section":"history","keywords":"LK-20260722-owner-minimal-validation-routing 2026-07-22 157 test compatible Test routing Test ownership","text":"Owner-minimal validation routing compiles canonical test groups id: LK-20260722-owner-minimal-validation-routing date: 2026-07-22 sequence: 157 type: test compatibility: compatible scope: Test routing scope: Test ownership Context Changed-file validation could widen an App capability change to a family-level test folder, depend on implicit contract discovery, or execute the same test through overlapping folder routes. The migration ledger recorded the required zero-debt replacement: explicit App owners, framework consumer closure, and one execution of each selected official test. Decision and rationale Treat route selection and execution as separate concerns. Preserve every semantic owner route with its reason, discover the matching official tests, then union canonical identities into one non-GUI and one hidden-GUI execution group. This keeps coverage reviewable without paying for duplicate execution. Changes Moved App-specific tests into explicit `appContract`, `workbench`, source capability, `smoke`, and `isolatedPath` owners; moved cross-App audits to project ownership. Removed family-root and overlap-based route suppression. Added canonical test-union compilation, deterministic feature-tagged smoke selection, direct facade-consumer routing, and safe all-smoke fallback when required feature metadata is absent. Preserved physical suite-folder case during selector discovery and made an isolated App sample derive the repository root from the shared test setup, so owner paths behave consistently on Linux, macOS, and Windows. Focused ordinary App-manual, history, and library-documentation routes while retaining complete contracts for renderer and policy changes. Added dynamic guards for every public App's owned contracts and smoke proof, valid source-capability scopes, unique canonical execution, and focused documentation routes. Test classes also reject migrated test-shaped methods stranded in non-discoverable static-private blocks. User and data impact No App behavior, saved project, scientific result, or export changes. Local `changedFast` feedback is smaller and deterministic; CI remains the complete headless and hidden-GUI validation gate. Compatibility and migration No saved-data migration is required. The active test-routing migration ledger is retired; future routing changes must extend the durable ownership rules and their guardrails rather than restore compatibility fallbacks. Validation Focused build-routing guardrails, App ownership contracts, and moved cross-App contracts. Same-machine MATLAB R2025a before/after benchmark for a representative Figure Studio source-capability change. One final `buildtool changedFast` run for the completed diff. Evidence The planner prints all semantic routes and the canonical execution count, including the number of repeated selections removed. The final local gate and CI provide the executable evidence for the exact merged diff. For a change to the Figure Studio `sourceAxes/copyToPreview` capability, the pre-migration planner at the retained mainline baseline selected 46 test executions across three runner groups: 45 unique tests plus one repeated isolated-path contract. Those groups took 120.396 seconds after 5.284 seconds of planning. The migrated planner retained four explicit semantic routes, selected 11 unique tests with no repeated execution, and compiled them into one headless and one hidden-GUI group. Those groups took 51.134 seconds after 6.212 seconds of planning. Test execution time fell by 69.262 seconds (57.5%) while retaining the source-capability unit tests, the owning App's isolated path contract, its launch smoke test, and the relevant source-axes GUI tests. Known limitations and follow-up Hidden GUI smoke tests validate bounded launch/layout behavior, not native dialogs, pointer feel, visual quality, or scientific interpretation; those remain manual review responsibilities."},{"title":"Preview-area per-axis wheel zoom","url":"history/records/2026/07/LK-20260709-preview-area-per-axis-wheel-zoom.html","kind":"history","section":"history","keywords":"LK-20260709-preview-area-per-axis-wheel-zoom 2026-07-09 44 feat compatible labkit.ui Preview-area per-axis wheel zoom","text":"Preview-area per-axis wheel zoom id: LK-20260709-preview-area-per-axis-wheel-zoom date: 2026-07-09 sequence: 44 type: feat compatibility: compatible component: `labkit.ui` | `5.0.3 -> 5.0.4` scope: Preview-area per-axis wheel zoom Context The preview area applied the same two-dimensional wheel zoom to every registered axes. That was appropriate for an image or main plot, but awkward for a narrow histogram or color-scale axes: horizontal zoom changed a dimension whose layout was meant to remain fixed. Decision and rationale Let a preview-area definition choose `xy`, `x`, or `y` wheel zoom for each axes. Preserve `xy` as the default so existing apps keep their behavior, while side axes can opt into only the dimension that carries data. Changes `labkit.ui` `5.0.3 -> 5.0.4` Added a `scrollZoomAxes` preview-area layout option so apps can declare whether each preview axis should mouse-wheel zoom in `xy`, `x`, or `y`. Preview-area side axes can now remain horizontally stable while still allowing app-selected vertical wheel zoom. User and data impact A histogram or temperature scale could remain horizontally stable while still supporting vertical exploration. Main images and plots continued to zoom in both dimensions unless their app explicitly chose another mode. Compatibility and migration Existing preview areas keep default `xy` wheel zoom unless they opt into another per-axis setting. Validation The commit extended UI layout unit tests and axes-workbench GUI coverage for the default and per-axis modes. The exact historical command was not recorded. Evidence Mainline commit `3c143eb`. Known limitations and follow-up The option controlled wheel navigation only. Toolbar zoom, pan, linked axes, and app-specific limit policies remained separate concerns."},{"title":"Profiling and validation speedups","url":"history/records/2026/07/LK-20260702-profiling-and-validation-speedups.html","kind":"history","section":"history","keywords":"LK-20260702-profiling-and-validation-speedups 2026-07-02 30 ci compatible labkit_launcher labkit_launcher labkit.ui labkit.ui labkit_BatchImageCrop_app labkit_ECGPrint_app Profiling and validation speedups","text":"Profiling and validation speedups id: LK-20260702-profiling-and-validation-speedups date: 2026-07-02 sequence: 30 type: ci compatibility: compatible component: `labkit_launcher` | `1.2.0 -> 1.2.1` component: `labkit_launcher` | `1.2.1 -> 1.2.2` component: `labkit.ui` | `3.4.0 -> 3.4.1` component: `labkit.ui` | `3.4.1 -> 3.4.2` component: `labkit_BatchImageCrop_app` | `1.6.0 -> 1.6.1` component: `labkit_ECGPrint_app` | `1.3.0 -> 1.3.1` scope: Profiling and validation speedups Context Startup and file-selection complaints could not be resolved reliably from wall clock impressions alone. At the same time, focused changes paid avoidable test discovery cost, GUI tests waited longer than the behavior required, and Batch Crop read every selected image before the user requested a preview or export. Decision and rationale Add a profiler that records launcher, startup, callback, and close costs with source attribution. Use its evidence to remove repeated UI updates and eager image reads. Route changed-file validation to the smallest owning suites and bound GUI waits without weakening their behavioral assertions. Changes `labkit_launcher` `1.2.0 -> 1.2.2` `labkit.ui` `3.4.0 -> 3.4.2` `labkit_BatchImageCrop_app` `1.6.0 -> 1.6.1` `labkit_ECGPrint_app` `1.3.0 -> 1.3.1` Added LabKit profiling and build-managed test routing to the launcher. Reduced GUI profiling overhead and deferred Batch Crop image reads until preview/export. Compressed validation runtime with bounded GUI waits. User and data impact Maintainers could launch a profiled target and receive a summarized report instead of interpreting MATLAB's raw profile table. Selecting many Batch Crop files returned sooner because images were decoded only for the current preview or final export. Routine validation also completed with less discovery and wait overhead. Compatibility and migration Profiling and test routing were maintainer tools. Batch Crop kept its task and export schemas; selected images were simply decoded later in the workflow. Validation The profiling tool received a dedicated unit suite. Later commits added launcher profiler coverage, deferred-read tests, debug-trace mirroring checks, routing guardrails, and bounded GUI-wait tests. Commit `25912c54` records successful `buildtool changed`, integration validation, and remote MATLAB tests. Evidence Main commits `c07dfc0a`, `74025fee`, `eadcca82`, `25912c54`, and `fcfc36d8`. Known limitations and follow-up These changes reduced measured work but did not eliminate the white window shown before all startup setup completed. The following startup pass changed when windows were painted and when scroll navigation was installed."},{"title":"Project restore distinguishes missing sources from damaged sources","url":"history/records/2026/07/LK-20260717-strict-project-session-restore.html","kind":"history","section":"history","keywords":"LK-20260717-strict-project-session-restore 2026-07-17 125 fix compatible labkit.ui labkit_FigureStudio_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageMatch_app labkit_ImageEnhance_app labkit_NerveResponseAnalysis_app Runtime project restore App session reconstruction","text":"Project restore distinguishes missing sources from damaged sources id: LK-20260717-strict-project-session-restore date: 2026-07-17 sequence: 125 type: fix compatibility: compatible component: `labkit.ui` | `7.4.6 -> 7.4.7` component: `labkit_FigureStudio_app` | `0.2.8 -> 0.2.9` component: `labkit_FLIRThermal_app` | `1.4.6 -> 1.4.7` component: `labkit_FocusStack_app` | `1.5.5 -> 1.5.6` component: `labkit_ImageMatch_app` | `1.6.6 -> 1.6.7` component: `labkit_ImageEnhance_app` | `1.6.6 -> 1.6.7` component: `labkit_NerveResponseAnalysis_app` | `1.4.6 -> 1.4.7` scope: Runtime project restore scope: App session reconstruction Context Runtime already resolved missing required source paths and offered interactive relinking before it rebuilt an App session. Several session factories then caught every decoder exception and returned an empty cache. A file that still existed but was damaged, unsupported, or exposed a programming error could therefore look like an unresolved source or an empty project. Decision and rationale Keep path resolution and cancellation in Runtime, and make reconstruction of an existing source strict. A session factory may accept an explicitly absent optional source, but it must not reinterpret an exception from an existing file. Runtime wraps reconstruction failures with `inputs.sources` IDs, roles, and filenames, records the exception in diagnostics, and preserves the prior state and presentation. Changes Removed broad exception recovery from Figure Studio, Focus Stack, Image Match, Image Enhance, FLIR Thermal, and Nerve Response Analysis session reconstruction. Made FLIR restore use strict thermal decoding while retaining skip-and-report behavior for interactive batch import. Added Runtime diagnostic context and a field-specific `ProjectSessionRestoreFailed` error without replacing the decoder cause. Added atomic corrupt-source, diagnostic-delivery, cross-App factory, and no-broad-catch regression coverage. User and data impact Missing required files still open the relink workflow, and cancelling it leaves the current project untouched. Existing corrupt or unsupported files now stop the load with the relevant project source identities and filenames instead of showing an empty preview. The prior document remains usable. App developers can leave ordinary decoder failures uncaught in `createSession.m`; Runtime owns the user-visible load failure and diagnostic record. Compatibility and migration No saved-project migration is required. Project envelopes and source-reference formats are unchanged. This change only corrects failure handling while reconstructing transient state. Validation Focused validation covers successful project round trips, missing-source relink, cancellation rollback, existing corrupt source rollback, diagnostic delivery, all affected session factories, and the repository guardrail that forbids broad catches in `createSession.m`. Evidence [Runtime and lifecycle](../../../../framework/guides/runtime.md#session-actions-presentation-and-renderers) [Figure Studio](../../../../apps/labkit-core/figure-studio/README.md) [FLIR Thermal](../../../../apps/image-measurement/flir-thermal/README.md) [Focus Stack](../../../../apps/image-measurement/focus-stack/README.md) [Image Match](../../../../apps/image-measurement/image-match/README.md) [Image Enhance](../../../../apps/image-measurement/image-enhance/README.md) [Nerve Response Analysis](../../../../apps/neurophysiology/nerve-response-analysis/README.md) Known limitations and follow-up Automated hidden GUI tests verify state rollback and semantic error delivery; they do not replace manual review of native dialog wording or damaged third-party file variants."},{"title":"Protected image enhancement workflows","url":"history/records/2026/06/LK-20260629-protected-image-enhancement-workflows.html","kind":"history","section":"history","keywords":"LK-20260629-protected-image-enhancement-workflows 2026-06-29 16 feat compatible labkit_ImageEnhance_app labkit_ImageMatch_app historical project evolution","text":"Protected image enhancement workflows id: LK-20260629-protected-image-enhancement-workflows date: 2026-06-29 sequence: 16 type: feat compatibility: compatible component: `labkit_ImageEnhance_app` | `1.2.2 -> 1.3.0` component: `labkit_ImageMatch_app` | `1.2.1 -> 1.3.0` scope: historical project evolution Context The existing appearance adjustments could change a subject together with its background. Image Enhance and Image Match needed modes that protected subject detail while correcting bright backgrounds and tone. Decision and rationale Add subject-preserving enhancement and protected tone matching as explicit methods with their own parameters, descriptions, and tests. Keep these methods inside the image apps because they encode workflow-specific decisions rather than generic image primitives. Changes Image Enhance `1.2.2 -> 1.3.0` Image Match `1.2.1 -> 1.3.0` Added Subject-preserving enhance to Image Enhance. Added Protected tone to Image Match. Added calculation and GUI coverage for both methods. User and data impact Users could brighten or normalize a background with less change to the main subject. The new methods were optional; existing histories and other matching methods retained their previous behavior. Compatibility and migration Existing enhancement steps and Image Match inputs remained valid. The new protected methods were additional choices and did not rewrite saved source images. Validation Commit `1768dd57` added focused Image Enhance and Image Match unit tests and updated both GUI workflow tests. Evidence Main commit `1768dd57`. Known limitations and follow-up The protected methods reduce unwanted subject changes but cannot infer semantic foreground perfectly. Their result still requires visual review."},{"title":"Public API help is complete, discoverable, and behavior checked","url":"history/records/2026/07/LK-20260717-complete-public-api-help-contract.html","kind":"history","section":"history","keywords":"LK-20260717-complete-public-api-help-contract 2026-07-17 127 docs compatible labkit.biosignal labkit.dta labkit.rhs labkit.thermal labkit.image labkit.ui labkit_DICPreprocess_app labkit_DICPostprocess_app labkit_CSC_app labkit_BatchImageCrop_app labkit_FLIRThermal_app labkit_ImageMatch_app labkit_VideoMarker_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app Public MATLAB help Generated API reference Documentation contract tests","text":"Public API help is complete, discoverable, and behavior checked id: LK-20260717-complete-public-api-help-contract date: 2026-07-17 sequence: 127 type: docs compatibility: compatible component: `labkit.biosignal` | `1.0.2 -> 1.0.3` component: `labkit.dta` | `2.0.2 -> 2.0.3` component: `labkit.rhs` | `1.0.2 -> 1.0.3` component: `labkit.thermal` | `1.1.1 -> 1.1.2` component: `labkit.image` | `2.0.1 -> 2.0.2` component: `labkit.ui` | `7.5.0 -> 7.5.1` component: `labkit_DICPreprocess_app` | `1.5.7 -> 1.5.8` component: `labkit_DICPostprocess_app` | `1.4.6 -> 1.4.7` component: `labkit_CSC_app` | `1.4.7 -> 1.4.8` component: `labkit_BatchImageCrop_app` | `1.7.6 -> 1.7.7` component: `labkit_FLIRThermal_app` | `1.4.7 -> 1.4.8` component: `labkit_ImageMatch_app` | `1.6.7 -> 1.6.8` component: `labkit_VideoMarker_app` | `1.5.6 -> 1.5.7` component: `labkit_NerveResponseAnalysis_app` | `1.4.7 -> 1.4.8` component: `labkit_ResponseReviewStats_app` | `1.4.6 -> 1.4.7` scope: Public MATLAB help scope: Generated API reference scope: Documentation contract tests Context LabKit's generated function pages came from MATLAB help, but the contract test covered a hand-maintained subset of packages and only checked broad section presence. A public function, implemented option, default, legal value, failure mode, or related API could therefore be omitted while the documentation suite still passed. Several App calculation pages exposed exactly those gaps. Decision and rationale Treat the callable public surface as discoverable source truth. The contract now scans every non-private function below `+labkit` plus each App API declared in the API catalog. It derives standard option reads from implementation code and requires those fields to have documented values and defaults, while required options remain explicitly distinguishable from optional ones. Every public function also states failure behavior and a `See also` relationship. This keeps a generated page useful for standalone MATLAB callers instead of merely repeating a short summary. Changes Completed help for the Contract, Biosignal, DTA, RHS, Thermal, Image, UI, and cataloged App calculation surfaces. Added exact option/default/legal-value checks, package-wide discovery, failure-behavior checks, and related-API checks to the documentation contract. Added a synthetic regression proving the guard detects an undocumented option, an omitted default, a vague value domain, missing failure behavior, and a missing related-API link. Made `labkit.image.resizeToFit` reject unsupported interpolation method names instead of silently treating them as bilinear. Linked owning library and App manuals to the detailed generated reference. User and data impact Readers can now determine valid calls, defaults, option domains, outputs, empty-result behavior, errors, and adjacent functions from the generated page for a public symbol. Developers adding a public function or a standard option read receive a focused contract failure when the corresponding help is incomplete. Compatibility and migration No saved project or data migration is required. Existing valid calls are unchanged. A call to `labkit.image.resizeToFit` with a method other than `\"bilinear\"` or `\"nearest\"` now raises `labkit:image:InvalidResizeMethod`; such values were never part of the documented contract. Validation The exact `PublicApiDocumentationContractTest` suite passes all eight tests, including execution of cataloged examples and the new synthetic defect regression. Image facade unit tests cover both supported resize methods and the unsupported-method error. Generated-site consistency and changed-scope validation are run after this record and its component manuals are rendered. Evidence [Public API index](../../../../reference/README.md) [LabKit App Framework](../../../../framework/README.md) [App catalog](../../../../apps/README.md) [Documentation maintenance](../../../../development/maintain-and-release/documentation.md) Known limitations and follow-up Implementation-derived option discovery intentionally recognizes the repository's standard option access patterns; unusual dynamic field access still requires review. Private helpers remain outside the public-page contract, and interactive `Typical Call:` sketches are not executed as file-independent examples. labkit.image.resizeToFit Resize an image to fit within maximum row/column limits."},{"title":"Public library help contracts and reference validation","url":"history/records/2026/07/LK-20260716-public-api-help-contracts.html","kind":"history","section":"history","keywords":"LK-20260716-public-api-help-contracts 2026-07-16 62 docs compatible labkit.biosignal labkit.dta labkit.image labkit.rhs labkit.thermal public MATLAB help generated API reference documentation contract tests","text":"Public library help contracts and reference validation id: LK-20260716-public-api-help-contracts date: 2026-07-16 sequence: 62 type: docs compatibility: compatible component: `labkit.biosignal` | `1.0.1 -> 1.0.2` component: `labkit.dta` | `2.0.1 -> 2.0.2` component: `labkit.image` | `2.0.0 -> 2.0.1` component: `labkit.rhs` | `1.0.1 -> 1.0.2` component: `labkit.thermal` | `1.1.0 -> 1.1.1` scope: public MATLAB help scope: generated API reference scope: documentation contract tests Context The public library reference identified functions and basic syntax but did not consistently explain option values, units, returned structures, failure behavior, or the distinction between executable examples and calls that need a user-supplied file. Readers still had to inspect implementation files to use several GUI-free APIs correctly. Decision and rationale Treat each public MATLAB help block as the source-level call contract and render that contract into one API page per function. Detailed library validation is kept separate from project-navigation validation so both remain focused and within the repository's effective-code-line budget. The patch versions record a compatible documentation-contract improvement. Function signatures, calculations, returned data, and error identifiers are unchanged. Changes Expanded public help with syntax, inputs, outputs, option names and legal values, defaults, units, errors, examples or typical calls, and related APIs. Distinguished self-contained `Example:` sections from interactive or file-dependent `Typical Call:` sections. Added generated-reference checks for thermal conversion and rendering, DTA schemas and pulse modes, and RHS lazy reads and waveform units. Corrected stale biosignal documentation links in package guidance and an implementation contract. Made label-ownership and package-boundary scans ignore prose-only substring collisions while continuing to reject literals and forbidden MATLAB tokens in executable code. User and data impact Users can discover the supported call contract through both `help` and the generated HTML reference without launching an app. No file format, saved project, calculation, or exported value changes. Compatibility and migration This is a patch-level compatible change. Existing calls require no migration. Validation Documentation consistency checks validate generated sections and executable examples. Project guardrails validate version/history ownership, literal ownership, package boundaries, and effective code-line budgets. Evidence Public help blocks and generated API pages are the maintained contract. Known limitations and follow-up Interactive calls and calls requiring laboratory files remain `Typical Call:` sketches until the repository provides synthetic, non-sensitive fixtures that make them executable examples."},{"title":"RHS Preview separates source roles from reference mechanics","url":"history/records/2026/07/LK-20260716-rhs-preview-structure.html","kind":"history","section":"history","keywords":"LK-20260716-rhs-preview-structure 2026-07-16 108 refactor compatible labkit_RHSPreview_app Neurophysiology App structure","text":"RHS Preview separates source roles from reference mechanics id: LK-20260716-rhs-preview-structure date: 2026-07-16 sequence: 108 type: refactor compatibility: compatible component: `labkit_RHSPreview_app` | `1.4.2 -> 1.4.3` scope: Neurophysiology scope: App structure Context RHS Preview split one durable project across generic lifecycle files and used two additional lifecycle helpers to select or replace records by role. It also constructed variable filter-source IDs itself and read Runtime-owned reference fields in session, actions, and presentation code. Product metadata remained in separate requirement/version functions. Decision and rationale Keep the three App-owned roles because they express real workflow meaning: one preview recording, one optional protocol, and an ordered collection of filter recordings. Use Runtime V2 for portable path access, fixed-source upserts, and stable reconciliation of the variable collection. Keep only the small App-owned role-to-path selection policy under `sourceFiles`; do not introduce a new framework public role API for one App-specific collection shape. Changes Consolidated command identity, display metadata, version, requirements, project, session, layout, actions, presenter, renderer, and debug capability through the single definition. Concentrated project creation, validation, and the version-1 source upgrade in `projectSpec` behind one `Migrate` callback. Moved indexing, initial preview reads, filter discovery, and transient view reconstruction to root `createSession`. Added `sourceFiles.pathsForRole` to select App-owned source roles while delegating reference decoding to `labkit.ui.runtime.sourcePaths`. Replaced fixed-source construction with `upsertSource` and variable filter ID construction with `reconcileSources`, preserving filter order and stable identities across rediscovery. Removed the generic lifecycle package and separate requirement/version files. User and data impact RHS indexing, lazy waveform windows, channel selection, managed ROI/scroll interaction, protocol editing, multi-file filter labels, refresh/removal, exports, manifests, reset, and project reopening retain their behavior. New filter selections use Runtime-generated stable IDs; those IDs are internal project identities and do not change exported recording paths or labels. The App version advances to 1.4.3; durable payload version remains 2. Compatibility and migration Version-1 projects still combine their separate recording, protocol, and filter source fields before validation. Existing version-2 source IDs and ordering are preserved when their resolved files remain selected. Runtime V2 owns migration iteration and later saves remain version 2. Validation Focused unit tests cover source migration, role-path ordering, summary/detail models, channel-role drafts, filter labels, and preview bounds. The hidden GUI workflow covers indexing and drawing a synthetic RHS file, channel tables, two-file filter discovery, protocol/filter export, manifests, project save, reset, reopen, and reconstruction of both preview and filter sources. Evidence [RHS Preview](../../../../apps/neurophysiology/rhs-preview/README.md) [Nerve Response Analysis](../../../../apps/neurophysiology/nerve-response-analysis/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) Known limitations and follow-up Automated tests do not assess native file-dialog feel, physical channel-role correctness, or waveform interpretation. The remaining special startup path and repository guidance still require separate convergence review."},{"title":"Release validation gate and GUI CI hardening","url":"history/records/2026/07/LK-20260708-release-validation-gate-and-gui-ci-hardening.html","kind":"history","section":"history","keywords":"LK-20260708-release-validation-gate-and-gui-ci-hardening 2026-07-08 40 ci compatible historical project evolution","text":"Release validation gate and GUI CI hardening id: LK-20260708-release-validation-gate-and-gui-ci-hardening date: 2026-07-08 sequence: 40 type: ci compatibility: compatible scope: historical project evolution Context Release-candidate tags did not yet require one explicit summary gate over the headless, coverage, and GUI jobs. Some GUI assertions also depended on exact pixel ordering or timing that varied across CI display backends. Decision and rationale Require every release test job before publication, while testing semantic grid structure instead of platform-specific pixel rounding. Increase the shared GUI idle allowance so slower hosted displays can finish registered UI work. Changes Project validation workflow, no component version change. Release candidate tags now run the full MATLAB test workflow gate before publication: headless tests, coverage, GUI tests, and a release summary gate. GUI layout tests now assert structural grid contracts instead of platform-dependent flattened pixel ordering or width comparisons. Shared GUI test idle waiting allows slower CI display backends more time to finish registered UI work. User and data impact Published release candidates gained a single pass/fail validation signal. Application behavior and data formats did not change; the GUI suite became less sensitive to harmless platform layout differences. Compatibility and migration No known manual migration. Validation Commit `f359518` updated CI policy tests, declarative UI tests, launcher GUI tests, and shared wait behavior. Evidence Mainline commit `f359518`. Known limitations and follow-up The gate covers automated checks only. Interactive workflow feel and scientific visual review remain outside hosted CI."},{"title":"Release validation includes Base MATLAB compatibility","url":"history/records/2026/07/LK-20260717-release-validation-hardening.html","kind":"history","section":"history","keywords":"LK-20260717-release-validation-hardening 2026-07-17 129 ci compatible scheduled and release-candidate validation","text":"Release validation includes Base MATLAB compatibility id: LK-20260717-release-validation-hardening date: 2026-07-17 sequence: 129 type: ci compatibility: compatible scope: scheduled and release-candidate validation Context LabKit already exposed `buildtool baseMatlab`, but GitHub Actions did not run the broad MATLAB product-ownership analysis. A release candidate could therefore pass headless, coverage, and GUI jobs while the explicit Base MATLAB compatibility gate remained a local-only check. Decision and rationale Run the existing public `baseMatlab` task in scheduled and manually dispatched workflows, and require it before a validated release tag can be created. Ordinary pull requests and main pushes retain the smaller headless gate because the static call scan and representative fallback workflows already run there. Changes Added a dedicated Base MATLAB compatibility job with JUnit, active-test, log, and artifact reporting. Added that job to the release-test dependency gate. Corrected the CI contract test so it discovers actual `tasks:` values and checks them against the executable build-task catalog. Updated artifact upload jobs to the current Node.js 24 action generation. User and data impact No App behavior or saved data changes. A release tag is now blocked when MATLAB resolves production source to an undeclared MathWorks product. Compatibility and migration The public `buildtool baseMatlab` command is unchanged. GitHub-hosted runners meet the action runtime requirement; no self-hosted runner migration is introduced. Validation The CI policy contract verifies job scope, public-task ownership, diagnostics, timeouts, parent checkout depth, and release-gate dependencies. The Base MATLAB task remains covered by its own dependency guardrail. Evidence `.github/workflows/matlab-tests.yml` is the executable release gate; `tests/cases/contract/project/ci/CiValidationPolicyGuardrailTest.m` protects its routing and dependency structure. Known limitations and follow-up The product-ownership analysis depends on MATLAB's dependency report and cannot replace manual scientific or interactive App validation."},{"title":"Response Review Stats uses one project contract","url":"history/records/2026/07/LK-20260716-response-review-structure.html","kind":"history","section":"history","keywords":"LK-20260716-response-review-structure 2026-07-16 105 refactor compatible labkit_ResponseReviewStats_app Neurophysiology App structure","text":"Response Review Stats uses one project contract id: LK-20260716-response-review-structure date: 2026-07-16 sequence: 105 type: refactor compatibility: compatible component: `labkit_ResponseReviewStats_app` | `1.4.2 -> 1.4.3` scope: Neurophysiology scope: App structure Context Response Review Stats kept project creation, validation, its one source-schema migration, and session reconstruction in four generic lifecycle files. Session and presentation code also read the Runtime's nested source path directly, and the reset action depended on the generic lifecycle package. Decision and rationale Use the standard compact Runtime V2 structure: one definition, one project contract, and one root session factory. Metric alignment, measurement, summaries, source parsing, exports, and presentation already had clear owners and remain unchanged. Changes Consolidated product metadata, version, requirements, layout, actions, presentation, renderer, and debug capability in `definition.m`. Concentrated project creation, validation, and the version-1 source upgrade in `projectSpec.m`. Moved transient metric/alignment reconstruction to root `createSession.m` and reused it for the reset action. Replaced direct portable-reference reads with semantic `sourcePaths` lookup. Removed the generic lifecycle package and separate requirement/version files. User and data impact Analysis JSON and segment CSV loading, automatic window recomputation, aligned preview, metric summaries, reset, output-folder choice, CSV export, and result manifest behavior are unchanged. Developers now see the entire durable schema history through one entry instead of four lifecycle files. Compatibility and migration Durable schema version 2 is unchanged. Version-1 projects still move their singular source to the canonical source collection before validation and the next save. Validation Focused tests cover source migration, segment parsing, time-grid alignment, measurement, pair-group summaries, and default-grid selection. The hidden GUI workflow loads representative metrics, presents them, and exports the CSV and manifest through real Runtime callbacks. Evidence [Response Review And Stats](../../../../apps/neurophysiology/response-review-stats/README.md) [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [Nerve Response Analysis](../../../../apps/neurophysiology/nerve-response-analysis/README.md) Known limitations and follow-up Automated checks do not validate biological interpretation of a chosen baseline/noise window. The larger RHS Preview and Nerve Response Analysis Apps still require independent ownership review."},{"title":"Runtime V2 lifecycle ownership across the app fleet","url":"history/records/2026/07/LK-20260715-runtime-v2-app-migration.html","kind":"history","section":"history","keywords":"LK-20260715-runtime-v2-app-migration 2026-07-15 59 refactor breaking labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app labkit_GaitAnalysis_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_VideoMarker_app labkit_FigureStudio_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app `docs/` `docs/ui-runtime-redesign.md` runtime migration guidance","text":"Runtime V2 lifecycle ownership across the app fleet id: LK-20260715-runtime-v2-app-migration date: 2026-07-15 sequence: 59 type: refactor compatibility: breaking component: `labkit.ui` | `5.2.0 -> 6.0.0` component: `labkit_DICPostprocess_app` | `1.3.6 -> 1.4.0` component: `labkit_DICPreprocess_app` | `1.4.0 -> 1.5.0` component: `labkit_ChronoOverlay_app` | `1.3.6 -> 1.4.0` component: `labkit_CIC_app` | `1.3.8 -> 1.4.0` component: `labkit_CSC_app` | `1.3.10 -> 1.4.0` component: `labkit_EIS_app` | `1.3.4 -> 1.4.0` component: `labkit_VTResistance_app` | `1.3.8 -> 1.4.0` component: `labkit_GaitAnalysis_app` | `1.0.0 -> 1.1.0` component: `labkit_BatchImageCrop_app` | `1.6.8 -> 1.7.0` component: `labkit_CurvatureMeasurement_app` | `1.3.5 -> 1.4.0` component: `labkit_FLIRThermal_app` | `1.3.0 -> 1.4.0` component: `labkit_FocusStack_app` | `1.4.9 -> 1.5.0` component: `labkit_ImageEnhance_app` | `1.5.8 -> 1.6.0` component: `labkit_ImageMatch_app` | `1.5.8 -> 1.6.0` component: `labkit_VideoMarker_app` | `1.2.0 -> 1.3.0` component: `labkit_FigureStudio_app` | `0.1.5 -> 0.2.0` component: `labkit_NerveResponseAnalysis_app` | `1.3.5 -> 1.4.0` component: `labkit_ResponseReviewStats_app` | `1.3.5 -> 1.4.0` component: `labkit_RHSPreview_app` | `1.3.4 -> 1.4.0` component: `labkit_ECGPrint_app` | `1.3.5 -> 1.4.0` scope: `docs/` scope: `docs/ui-runtime-redesign.md` scope: runtime migration guidance Context App lifecycle, callback ordering, UI-derived state, project persistence, graphics resources, and result packaging were implemented repeatedly across apps. Migrating only the lifecycle names would have preserved the main author cost: each app would still need to understand raw controls, figure callbacks, and multiple competing state copies. Decision and rationale Make Runtime V2 the only write path and give the framework ownership of launch, startup, the FIFO event queue, atomic state commits, deterministic presentation, dialogs, interaction resources, project persistence, and result manifests. Apps retain explicit project/session/presentation/result contracts and all domain calculations, workflow decisions, plots, schemas, and exports. This deliberately optimizes ownership and learning cost rather than total app line count. Explicit app contracts can add code in a large scientific app, but they replace hidden closure state and callback plumbing with one inspectable model. The remaining 36 public UI functions have distinct reviewed contracts; the earlier 32-function planning target was not forced through vague APIs. Changes Migrated all twenty public apps to Runtime V2 definitions, standard launch, canonical project/session state, semantic events, pure presentation, and managed resources. Standardized current project writes and result manifests while retaining app-owned payload migrations and existing output files. Retired Runtime V1 writes and removed the public control-registry mutation, standalone editor/runtime, preview mutation, dialog, title, and dispatch compatibility surfaces. Kept supported V1 snapshots and named legacy app projects as read-only import formats; subsequent saves use the current project codec. Updated app requirements to `labkit.ui >=6 <7` and made UI 6 the breaking public facade boundary. Replaced Video Marker's optional `vision.PointTracker` branch with one deterministic app-owned multiscale patch matcher, retaining confidence, constant-velocity fallback, subpixel coordinates, and forward-cache behavior without Computer Vision Toolbox. Added traceable temporary MathWorks-product debt declarations: rapid app work must ship a base-MATLAB fallback plus deterministic and Toolbox-parity tests, and product analysis must continue to see the dependency until replacement. Re-audited already migrated apps, removed five dead or presenter-only helper files, and updated helper-quality classification from retired role packages to the current workflow-first lifecycle/state/result/UI boundaries. Corrected Runtime V2 interaction event construction so paired-anchor cell payloads remain one scalar semantic event. DIC Preprocess point matching now accepts alternating reference/moving points, enables alignment after two complete pairs, and completes the in-workbench rigid registration flow. Hardened the same scalar-envelope invariant for app-managed Runtime V2 resources and `runBusy` callback capture, including legitimate cell-form MATLAB callbacks and cell-valued resource payloads. Made project replacement invalidate the prior presentation cache before the fresh session is rendered, so opening an unchanged project still rebuilds app-owned preview graphics and other ephemeral visual resources. Corrected shared file-event index decoding for R2025a string results, so CIC and the other multi-file V2 apps can select and remove imported items. Stopped presentation commits from rerunning unchanged preview requests, and made DIC point-label updates preserve image handles and zoom viewports. Routed anchor-editor wheel input to the shared image zoom implementation without the retired wrapper's same-name recursion. Deferred CIC and VT batch DTA decoding until a file becomes visible or the batch is exported, so multi-file selection no longer blocks on every source. Let Gait Analysis read current Video Marker project/recovery envelopes and legacy Video/Image Marker autosaves directly as pose-coordinate inputs. Added interaction-mode subtitles for curve anchors, point marking, paired anchors, scale references, and fixed point slots; restored axes context menus after renderer resets; and promoted screenshot/project commands to top-level window entries. Moved Video Marker's Session controls to the top of the Video page, added an `Open MAT` project shortcut, and made New setup explicitly cancel, save, or discard before clearing the current project. Reorganized human documentation into getting-started, app workflow, public API, development, and focused-guide layers. Split app authoring from the user catalog, added the missing contract API reference, and made a project guardrail verify that every public `+labkit` function remains indexed under its owning facade. User and data impact App entrypoint names, scientific calculations, workflow decisions, plots, and existing export filenames remain stable. Current projects have a consistent save/reopen path, external sources use portable references, and result exports include a standard manifest. Runtime errors and modal interactions now pass through framework services, which also makes hidden validation deterministic. Compatibility and migration The migrated app versions require `labkit.ui >=6 <7`; they must not be copied into a UI 5 checkout. Supported V1 snapshots and documented legacy projects remain importable but are not written again. After import, save a new current project if continued editing or recovery is required. Validation Focused Runtime V2, project, interaction-hub, DIC point-matching, CIC, Figure Studio, app-boundary, and public-surface tests passed. The latest repair checkpoint additionally passed CIC/VT GUI workflows (2/2), Gait/app compatibility tests (21/21), Curvature and Video Marker GUI methods (6/6), focused framework menu/interaction tests (8/8), and three targeted interaction-hint methods (3/3). A real local legacy Video Marker autosave was read successfully without copying it into the repository. The documentation hierarchy checkpoint passed relative-link validation and 44/44 focused documentation, app-structure, build-task, and history guardrails. The Phase-6 `buildtool changedFast` checkpoint passed 15 framework GUI tests, 284 headless tests with one environment-assumption skip, and six representative GUI workflows. The final broad gate and any manual pointer or visual checks are reported with the merge handoff rather than embedded as mutable history. Video Marker replacement tests exercise integer and subpixel translation, flat-patch fallback, repeated-input determinism, prediction caching, and coordinate parity with `vision.PointTracker` when that product is installed. `buildtool baseMatlab` confirms the production source resolves only to MATLAB. Evidence `4454ca30` introduced the Runtime V2 kernel; the app migrations then ran from Chrono Overlay (`5fe76ee4`) through Figure Studio (`21936e8d`). `1ef46bfd` removed the retired UI runtime, and `8e109ff4` completed the framework contracts used by the migrated apps. The commits listed in the migration sequence above preserve the individual app checkpoints; this record explains their shared architectural result. Known limitations and follow-up Explicit domain contracts mean that large apps do not necessarily have fewer production lines. Further extraction is justified only by repeated mechanics, not by file-size targets. Pointer feel, drag ergonomics, and scientific visual judgment still require the documented manual app review before merge."},{"title":"Runtime exposes GUI-free source-record creation","url":"history/records/2026/07/LK-20260716-gui-free-source-records.html","kind":"history","section":"history","keywords":"LK-20260716-gui-free-source-records 2026-07-16 100 feat compatible labkit.ui Runtime V2 sources App project migration","text":"Runtime exposes GUI-free source-record creation id: LK-20260716-gui-free-source-records date: 2026-07-16 sequence: 100 type: feat compatibility: compatible component: `labkit.ui` | `7.4.1 -> 7.4.2` scope: Runtime V2 sources scope: App project migration Context Runtime V2 owned the portable-reference schema and exposed a stable path accessor, but source-record creation was available only through callback-bound project services. GUI-free project migrations and legacy importers therefore could not create canonical sources without copying private reference fields. Batch Crop and Video Marker both contained such schema copies. Decision and rationale Expose the canonical source record, not the portable-reference implementation. `labkit.ui.runtime.sourceRecord` accepts stable App identity, semantic role, path, and required status, then delegates the nested representation to the Runtime. The injected callback service uses the same factory. Changes Added the GUI-free `labkit.ui.runtime.sourceRecord` factory with validation and complete MATLAB help. Routed `services.project.sourceRecord`, `upsertSource`, and `reconcileSources` through the same public contract. Extended source tests to cover factory output and invalid inputs. Updated the framework API map and portable-source guidance. User and data impact User project behavior is unchanged. App authors can now implement project migrations and legacy imports without opening a UI callback or constructing runtime-owned reference fields. Current file paths remain available only through `sourcePaths`. Compatibility and migration The addition is compatible within UI 7. Existing source records and injected services retain their shape and behavior. Apps should replace copied portable reference construction when their project/import code is migrated. Validation Focused Runtime source tests cover empty arrays, canonical creation, resolved path lookup, ordered/optional ID lookup, invalid references, and invalid factory arguments. Package-surface, version, documentation, and history guardrails protect the new public contract. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [App Framework](../../../../framework/README.md) [Architecture](../../../../development/build-apps/architecture.md) Known limitations and follow-up Existing Apps that still copy or read portable-reference fields must migrate to `sourceRecord` and `sourcePaths` before the legacy source boundary is fully retired."},{"title":"Runtime owns portable source-reference details","url":"history/records/2026/07/LK-20260716-source-path-accessor.html","kind":"history","section":"history","keywords":"LK-20260716-source-path-accessor 2026-07-16 91 feat compatible labkit.ui Runtime source boundary App maintenance cost","text":"Runtime owns portable source-reference details id: LK-20260716-source-path-accessor date: 2026-07-16 sequence: 91 type: feat compatibility: compatible component: `labkit.ui` | `7.3.0 -> 7.4.0` scope: Runtime source boundary scope: App maintenance cost Context Runtime V2 owned source creation, rebasing, relinking, and validation, but an App still had to read `reference.originalPath` whenever it loaded or displayed a source. This exposed the nested persistence representation throughout session factories, actions, presenters, and workflow packages. Several Apps then added their own identical path loops or ID lookup functions. Decision and rationale Keep source `id`, `role`, and `required` as stable App-facing project data, but treat the nested portable reference as a runtime-owned value. Add one pure `labkit.ui.runtime.sourcePaths` accessor that works before UI construction and therefore serves session creation as well as actions and presentation. Passing UI-bound injected services into `CreateSession` was rejected: it would couple otherwise pure state reconstruction to figure, queue, dialog, and resource-service construction merely to read a path. Changes Added `sourcePaths(sources)` for paths in source order. Added `sourcePaths(sources,ids)` for strict lookup in requested ID order. Defined empty, malformed-reference, and unknown-ID behavior in executable public help and unit tests. Stopped documenting portable-reference fields as an App read contract. Added the accessor to the guarded public UI runtime surface. User and data impact Saved projects and file resolution behave unchanged. App code can now read, compare, load, and present source paths without knowing how a portable reference stores its current or relative location. Compatibility and migration The addition is compatible within UI 7. Existing direct field reads continue to work temporarily, but tracked Apps will move to the accessor during their family-by-family Runtime V2 consolidation. No project migration is required. Validation Unit tests cover source order, requested ID order, empty results, missing IDs, and invalid runtime references. Package-surface and documentation guardrails cover the new public contract. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) [Complete App Tutorial](../../../../development/build-apps/complete-app.md) Known limitations and follow-up Existing App-local path loops remain until their owning App commits are migrated and behavior-tested. Once all consumers use this accessor, a contract guard will prevent production Apps from reading portable-reference fields."},{"title":"Runtime uses one source contract for launch, migration, and layout","url":"history/records/2026/07/LK-20260717-retired-runtime-compatibility.html","kind":"history","section":"history","keywords":"LK-20260717-retired-runtime-compatibility 2026-07-17 126 refactor breaking labkit.ui Runtime launch contract Project payload migration Semantic layout validation","text":"Runtime uses one source contract for launch, migration, and layout id: LK-20260717-retired-runtime-compatibility date: 2026-07-17 sequence: 126 type: refactor compatibility: breaking component: `labkit.ui` | `7.4.7 -> 7.5.0` scope: Runtime launch contract scope: Project payload migration scope: Semantic layout validation Context UI Runtime had already introduced one-definition App launch, one version-aware `Project.Migrate` callback, and presenter-owned managed interactions. Transitional branches still accepted separate requirements and version factories, ordered `Project.Migrations` cells, and a `toolPanel` layout kind whose public constructor no longer existed. No public or accepted private App used those branches; framework tests and stale guidance were their only remaining consumers. Decision and rationale Keep one writable source contract for each capability. `launch` receives one definition factory and reads product metadata and requirements from that definition. Runtime calls the App's single `Migrate(project,fromVersion)` callback for each missing payload step. Layout sections contain supported semantic controls, while presenter interaction specs own axes tools. This removes source-level compatibility that could hide an incomplete App migration. Read-only support for current saved project envelopes, declared legacy MAT imports, and older supported payload versions remains intact. Changes Removed requirements/version factory dispatch from `runtime.launch` and added a direct diagnostic for the retired call form. Rejected `Project.Migrations` and removed its project-reader fallback. Removed `toolPanel` validation, sizing, building, diagnostics, and current manual guidance. Converted Runtime tests to complete single definitions and added regression checks for both retired contracts. User and data impact Current Apps and their project files behave the same. App developers have one place to review identity, version, requirements, layout, and optional runtime capabilities. Source code still using a three-factory launch or `Project.Migrations` now fails immediately with migration guidance instead of silently taking a legacy path. Compatibility and migration This is a source-contract cleanup within UI 7. Call `labkit.ui.runtime.launch(@app.definition,varargin{:})`, move product metadata and `Requirements` into `definition.m`, and replace migration callback cells with one callback that switches on `fromVersion`. No saved-data rewrite is required. Validation Focused Runtime GUI tests cover single-definition launch, rejection of the retired launch form, ordered project migration and atomic load, rejection of `Project.Migrations`, managed interactions, and startup progress. Contract tests cover App layout structure and public surface drift. Evidence [Runtime and lifecycle](../../../../framework/guides/runtime.md) [App development](../../../../development/build-apps/app-development.md) [Public API reference](../../../../reference/README.md) Known limitations and follow-up Historical records retain their original descriptions of the transitional APIs. They document how the architecture evolved and are not current usage guidance."},{"title":"Runtime-only P-code app packages","url":"history/records/2026/07/LK-20260708-runtime-only-p-code-app-packages.html","kind":"history","section":"history","keywords":"LK-20260708-runtime-only-p-code-app-packages 2026-07-08 41 refactor compatible historical project evolution","text":"Runtime-only P-code app packages id: LK-20260708-runtime-only-p-code-app-packages date: 2026-07-08 sequence: 41 type: refactor compatibility: compatible scope: historical project evolution Context Single-app P-code packages included a P-coded copy of the full launcher even though their purpose was to run one protected app. That exposed maintenance and packaging actions that were meaningful only in a source checkout. Decision and rationale Make P-code output a minimal runtime package with a direct app entry script. Keep the full launcher in source and source-package distributions, where its installation, profiling, and packaging tools are available. Changes Project deployment tooling, no component version change. `Package P-code` now creates a runtime-only single-app package instead of shipping a P-coded LabKit launcher and launcher maintenance tools. P-code package manifests and README instructions point users to the direct `run_` entry file. P-code packaging no longer requires `labkit_launcher.m` or `labkit_launcher.p` to exist in the package root being used as the runtime source. User and data impact Recipients of a P-code package start the protected app with `run_` and no longer see unrelated launcher maintenance actions. The protected app and its data formats are unchanged. Compatibility and migration Users of P-code packages should run `run_` from the unzipped package instead of `labkit_launcher`. Source packages still include and support the launcher. Validation Commit `75f63f1` expanded `PackageLabKitAppToolTest` for runtime-only package contents and updated the generated package instructions. Evidence Mainline commit `75f63f1`. Known limitations and follow-up P-code packages intentionally omit source-oriented launcher features. Users who need installation or packaging tools should use a source or source-package distribution."},{"title":"Runtime-owned project shape validation","url":"history/records/2026/07/LK-20260716-runtime-owned-project-shape-validation.html","kind":"history","section":"history","keywords":"LK-20260716-runtime-owned-project-shape-validation 2026-07-16 117 refactor compatible labkit.ui labkit_ChronoOverlay_app labkit_CIC_app labkit_CSC_app labkit_EIS_app labkit_VTResistance_app Runtime V2 project validation electrochemistry App maintenance cost","text":"Runtime-owned project shape validation id: LK-20260716-runtime-owned-project-shape-validation date: 2026-07-16 sequence: 117 type: refactor compatibility: compatible component: `labkit.ui` | `7.4.4 -> 7.4.5` component: `labkit_ChronoOverlay_app` | `1.4.4 -> 1.4.5` component: `labkit_CIC_app` | `1.4.4 -> 1.4.5` component: `labkit_CSC_app` | `1.4.4 -> 1.4.5` component: `labkit_EIS_app` | `1.4.4 -> 1.4.5` component: `labkit_VTResistance_app` | `1.4.4 -> 1.4.5` scope: Runtime V2 project validation scope: electrochemistry App maintenance cost Context Runtime already validated canonical project buckets and portable source records after actions committed. During project restore, however, the App validator ran before that framework validation. Every persistent App consequently repeated the same bucket and source-record checks so malformed loaded projects would fail safely. Decision and rationale Validate framework-owned project structure before invoking App-owned project validation on both initial state and project restore. App validators should describe only their own schema and scientific rules. This gives canonical shape and source records one owner while retaining strict validation at the load boundary. Changes Added one private Runtime project-shape validator shared by restore and semantic state validation. Runtime now rejects a malformed loaded payload before its App validator can inspect domain fields. Removed 67 net lines of repeated canonical bucket and source-record checks from the five electrochemistry `projectSpec.m` files. Kept each App's legal choices, numeric bounds, result fields, and other domain-specific validation unchanged. User and data impact Valid projects and scientific results are unchanged. Malformed projects now receive the framework's consistent invalid-state error for canonical structure failures instead of an App-specific bucket or source error. No payload migration is required. Compatibility and migration The accepted project schema is unchanged. This is a validation-ownership change, not a data-format change, and current or older supported project versions continue through the same migration callbacks. Validation The Runtime project GUI test loads a payload missing a canonical bucket and verifies atomic rejection before App validation. Focused electrochemistry GUI tests exercise load, analysis, plotting, and export paths with the reduced App validators. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) defines the framework and App validation boundary. [App Development](../../../../development/build-apps/app-development.md) tells App authors which validation remains in `projectSpec.m`. Each affected [Electrochemistry App](../../../../apps/electrochemistry/README.md) manual identifies its domain-owned validator responsibilities. Known limitations and follow-up Other App families still repeat some canonical structure checks. They will move to the same boundary only after their role and cross-field constraints are separated from the generic checks and covered by focused tests."},{"title":"Runtime-owned session defaults across App families","url":"history/records/2026/07/LK-20260716-runtime-owned-session-defaults.html","kind":"history","section":"history","keywords":"LK-20260716-runtime-owned-session-defaults 2026-07-16 116 refactor compatible labkit.ui labkit_DICPostprocess_app labkit_DICPreprocess_app labkit_GaitAnalysis_app labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FLIRThermal_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app labkit_VideoMarker_app labkit_FigureStudio_app labkit_NerveResponseAnalysis_app labkit_ResponseReviewStats_app labkit_RHSPreview_app labkit_ECGPrint_app Runtime V2 session construction App maintenance cost","text":"Runtime-owned session defaults across App families id: LK-20260716-runtime-owned-session-defaults date: 2026-07-16 sequence: 116 type: refactor compatibility: compatible component: `labkit.ui` | `7.4.3 -> 7.4.4` component: `labkit_DICPostprocess_app` | `1.4.3 -> 1.4.4` component: `labkit_DICPreprocess_app` | `1.5.4 -> 1.5.5` component: `labkit_GaitAnalysis_app` | `2.0.4 -> 2.0.5` component: `labkit_BatchImageCrop_app` | `1.7.3 -> 1.7.4` component: `labkit_CurvatureMeasurement_app` | `1.4.3 -> 1.4.4` component: `labkit_FLIRThermal_app` | `1.4.3 -> 1.4.4` component: `labkit_FocusStack_app` | `1.5.2 -> 1.5.3` component: `labkit_ImageEnhance_app` | `1.6.3 -> 1.6.4` component: `labkit_ImageMatch_app` | `1.6.3 -> 1.6.4` component: `labkit_VideoMarker_app` | `1.5.2 -> 1.5.3` component: `labkit_FigureStudio_app` | `0.2.5 -> 0.2.6` component: `labkit_NerveResponseAnalysis_app` | `1.4.3 -> 1.4.4` component: `labkit_ResponseReviewStats_app` | `1.4.3 -> 1.4.4` component: `labkit_RHSPreview_app` | `1.4.3 -> 1.4.4` component: `labkit_ECGPrint_app` | `1.4.3 -> 1.4.4` scope: Runtime V2 session construction scope: App maintenance cost Context Runtime V2 already adds the canonical `selection`, `workflow`, `view`, and `cache` session buckets after an App factory returns. Its workflow service also creates `logLines` on the first log operation. Fifteen App factories still repeated empty buckets or initialized that framework-owned log, making their state declarations longer and obscuring which transient fields were genuinely App-specific. Decision and rationale Treat canonical session shape and workflow-log initialization as Runtime control-plane responsibilities. An App session factory now returns only the selection, workflow, view, and cache fields that express its own workflow. This preserves explicit App state while removing framework boilerplate. Changes Removed empty canonical session buckets from affected App factories. Removed every App-owned `logLines` initializer; the injected workflow service remains the only writer and lazy initializer. Removed Image Enhance's direct log-panel presenter binding; Runtime commits the workflow log to every declared log panel. Added `services.project.newState()` and moved full-project reset actions onto that Runtime-owned creation and normalization path. Added a fleet-wide structure guard that rejects empty canonical buckets and direct workflow-log initialization in `createSession.m`. Updated every affected App manual and patch version. User and data impact There is no workflow, scientific, persistence, or saved-data change. Runtime normalization produces the same complete in-memory session before validation, presentation, or the first callback. Existing project files remain compatible. Compatibility and migration The change is source-compatible within Runtime V2 and requires no project payload migration. Direct tests of an App's raw session factory should inspect only App-owned fields; tests that need canonical empty buckets should create state through Runtime. Validation The fleet structure guard covers every public App factory. Focused App unit and hidden-GUI suites verify restored state, initial presentation, workflow logs, and representative source-backed sessions across the affected families. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) defines canonical session normalization and workflow logging. [App Development](../../../../development/build-apps/app-development.md) requires `createSession.m` to rebuild only App-specific transient data. Each affected App manual describes its remaining session-owned fields. Known limitations and follow-up Most factories still perform necessary source decoding or reconstruction. They should not be removed merely to reduce file count. Further simplification requires evidence that a repeated reconstruction pattern is domain-neutral and belongs behind a stable Runtime service."},{"title":"Searchable MATLAB-generated documentation site and launcher workflow groups","url":"history/records/2026/07/LK-20260715-documentation-site.html","kind":"history","section":"history","keywords":"LK-20260715-documentation-site 2026-07-15 60 feat compatible labkit_launcher `docs/` `site/` `tools/docs/` `buildfile.m`","text":"Searchable MATLAB-generated documentation site and launcher workflow groups id: LK-20260715-documentation-site date: 2026-07-15 sequence: 60 type: feat compatibility: compatible component: `labkit_launcher` | `1.4.0 -> 1.5.0` scope: `docs/` scope: `site/` scope: `tools/docs/` scope: `buildfile.m` Context The documentation had become a set of large Markdown pages with no generated site, global search, code-entity pages, or enforced relationship between the public MATLAB surface and its reference material. Launcher actions were also presented as a mostly flat list, making routine app launch, installation, maintenance, profiling, and packaging appear equally related. Decision and rationale Keep authoring in tracked Markdown, structured navigation/catalog metadata, and MATLAB help blocks, then use one repository-owned MATLAB compiler to emit the tracked static site. Bind every non-private `labkit.*` API and each explicitly cataloged app-owned scientific API to its source declaration. Keep private helpers out of detailed reference pages. Group launcher actions by user intent and make documentation regeneration a first-level maintenance action. This follows the separation used by MATLAB and Qt documentation while keeping the build offline and dependency-free. Changes Added a MATLAB-only static documentation compiler, responsive site chrome, global client-side search, source links, related-API links, and deterministic generated-tree comparison. Added structured page and app-owned API catalogs. Generated reference now covers reusable library functions plus explicitly supported GUI-free app calculation entry points, while rejecting `private/` paths. Added public documentation build and consistency tasks and project guardrails for catalog coverage, search visibility, and generated output. Reorganized launcher buttons into Run Apps, Versions and Install, Development and Maintenance, and Package and Publish groups. Added Update Documentation to the launcher. It rebuilds `site/`, opens the generated home page, and reports narrative-page, API-page, file, and output location details. User and data impact Users can browse and search documentation without a MATLAB documentation server, move between related public functions, and regenerate the same site after source changes. Existing app data, projects, calculations, and exports are unchanged. Launcher maintenance actions are easier to distinguish from normal app launch and installation tasks. Compatibility and migration The feature is additive. Existing Markdown links remain valid in the source repository. `site/` is generated and must not be edited manually. Source-only or P-code app packages that omit documentation tools show the launcher action disabled with an explanatory tooltip. Validation The compiler generated 20 narrative pages, 133 public API pages, and 157 tracked files. Focused documentation/build guardrails passed after verifying a byte-for-byte rebuild. Hidden-GUI launcher layout, documentation generation, and missing-tool behavior tests passed 3/3. Evidence `tools/docs/renderLabKitDocs.m` and `docs/site.json` define the deterministic build and navigation contract. `docs/catalogs/api.json` defines the supported app-owned public API surface. Initial searchable site and launcher integration `bdeba572`. Per-app documentation publication `82734a47`. Later information-architecture rebuild `8b55e2b9`. Known limitations and follow-up The first generated site still contains transitional narrative pages that must be split into app-family, per-app, framework, and focused API guides. Cataloged scientific APIs need richer standalone examples and algorithm/unit sections before the documentation rewrite is complete."},{"title":"Shared image facade","url":"history/records/2026/06/LK-20260630-shared-image-facade.html","kind":"history","section":"history","keywords":"LK-20260630-shared-image-facade 2026-06-30 24 feat compatible labkit.image labkit_BatchImageCrop_app labkit_CurvatureMeasurement_app labkit_FocusStack_app labkit_ImageEnhance_app labkit_ImageMatch_app historical project evolution","text":"Shared image facade id: LK-20260630-shared-image-facade date: 2026-06-30 sequence: 24 type: feat compatibility: compatible component: `labkit.image` | `new -> 1.0.0` component: `labkit_BatchImageCrop_app` | `1.3.9 -> 1.4.0` component: `labkit_CurvatureMeasurement_app` | `1.2.3 -> 1.2.4` component: `labkit_FocusStack_app` | `1.2.5 -> 1.3.0` component: `labkit_ImageEnhance_app` | `1.3.5 -> 1.4.0` component: `labkit_ImageMatch_app` | `1.3.5 -> 1.4.0` scope: historical project evolution Context Batch Crop, Focus Stack, Image Enhance, and Image Match each carried similar code for supported extensions, path normalization, image reads, preview sizing, and basic enhancement. Small differences between those copies produced inconsistent file and display behavior. Decision and rationale Introduce `labkit.image` for GUI-free operations with neutral meaning, then move the image apps to that shared API. Keep crop geometry, focus fusion, matching, protected enhancement, and export schemas in their respective apps. Changes `labkit.image` `1.0.0` Batch Crop, Curvature, Focus Stack, Image Enhance, and Image Match advanced within their image-facade adoption lines. Added a GUI-free image facade for file input, display normalization, basic processing, and preview support. Adopted that facade across image-measurement apps. User and data impact Supported image selection, display-name handling, preview normalization, and common enhancement primitives became consistent across the migrated apps. Scientific app outputs and source files did not change format. Compatibility and migration Image apps kept their entry points and exports while adopting the shared operations. App code that called the retired local helpers needed to use the image facade or the owning app operation. Validation Commit `7023e87e` added a dedicated `LabKitImageFacadeTest` suite and updated app compatibility, package-boundary, public-surface, and focused image-app tests. Evidence Main commit `7023e87e`. Known limitations and follow-up The first facade release covered common MATLAB image formats and basic processing only. Thermal decoding and workflow-specific algorithms remained outside `labkit.image`."},{"title":"Single-click DIC rigid point matching","url":"history/records/2026/07/LK-20260713-dic-rigid-point-editor.html","kind":"history","section":"history","keywords":"LK-20260713-dic-rigid-point-editor 2026-07-13 50 feat compatible labkit.ui labkit_DICPreprocess_app Single-click DIC rigid point matching","text":"Single-click DIC rigid point matching id: LK-20260713-dic-rigid-point-editor date: 2026-07-13 sequence: 50 type: feat compatibility: compatible component: `labkit.ui` | `5.0.4 -> 5.1.0` component: `labkit_DICPreprocess_app` | `1.3.6 -> 1.4.0` scope: Single-click DIC rigid point matching Context DIC manual rigid matching had draggable points but maintained a separate pointer implementation and required a less consistent placement workflow than the ROI-center anchors used by Imager Reconstruction. Decision and rationale Extend the existing app-neutral anchor editor with a discrete point mode, then keep moving/fixed pair order, numbering, minimum pair count, and rigid-fit policy inside DIC. Changes Added `mode=\"points\"`: one blank click appends a point, dragging refines it, no connecting curve is drawn, and deletion remains under explicit controls. Migrated the DIC modal to two shared point-mode editors while preserving ordered moving/fixed pairs, labels, undo, cancel, and acceptance rules. Retained toolbox-free image display and rigid alignment behavior. User and data impact Feature placement now follows the same direct click-and-drag model as Imager ROI anchors. Point coordinates and the resulting rigid transform keep their existing N-by-2 pixel-coordinate contract. Compatibility and migration The default anchor-editor curve mode is unchanged. DIC exports and transform math are unchanged; this is an additive interaction improvement. Validation UI anchor-editor tests cover discrete point append and no-path behavior. The DIC GUI workflow covers toolbox-free modal cancellation and app launch wiring. Evidence Primary sources are `labkit.ui.interaction.anchorEditor` and `dic_preprocess.userInterface.selectRigidPointPairs`. Commit `392a073e` introduced their shared DIC rigid-point interaction. Known limitations and follow-up Automated hidden-GUI tests cannot judge pointing ergonomics; final interaction feel still requires a short manual placement-and-drag check."},{"title":"Single-definition App product contract","url":"history/records/2026/07/LK-20260716-single-definition-contract.html","kind":"history","section":"history","keywords":"LK-20260716-single-definition-contract 2026-07-16 77 feat compatible labkit.ui App authoring Runtime V2 launch metadata","text":"Single-definition App product contract id: LK-20260716-single-definition-contract date: 2026-07-16 sequence: 77 type: feat compatibility: compatible component: `labkit.ui` | `7.1.0 -> 7.2.0` scope: App authoring scope: Runtime V2 launch metadata Context Every App repeated product metadata and facade requirements in `version.m` and `requirements.m`, while `definition.m` separately described the product's runtime behavior. Thin entrypoints had to join all three factories, and the launcher and release guardrails treated the duplicate files as separate facts. Decision and rationale Make `definition.m` the one App product contract. Product identity, version, requirements, layout, and optional runtime capabilities now have one owner. The public entrypoint can delegate through `launch(@definition, varargin{:})`. Changes Added `Command`, optional `DisplayName`, `Family`, `AppVersion`, `Updated`, and `Requirements` fields to `labkit.ui.runtime.define`. Added single-definition launch and lightweight `version` and `requirements` request handling. Kept the previous three-factory launch form only as a temporary bridge while existing Apps move in reviewed family-sized changes. Extended the minimal real-GUI launch test to obtain all metadata from the same definition. User and data impact App users see no workflow or scientific change. App authors no longer need to keep three product declarations synchronized after their App is migrated. Compatibility and migration The addition is compatible within UI 7. Existing definitions continue to run during the migration window. Each App will move its exact metadata and facade ranges into `definition.m` before its redundant files are removed. The bridge is not a permanent supported architecture. Validation Focused runtime tests exercise normal launch plus `version` and `requirements` requests from one minimal definition. Documentation, facade-version, and App contract tests protect the metadata shape during the family migrations. Evidence [Runtime and Lifecycle](../../../../framework/guides/runtime.md) documents the single definition and field meanings. [App Development](../../../../development/build-apps/app-development.md) shows the reduced static App file set. Known limitations and follow-up Existing Apps, launcher static discovery, release version guards, tutorials, and the App-builder skill still need family-by-family migration. The legacy launch bridge is removed only after those consumers no longer use it."},{"title":"Source-adjacent Video Marker autosave","url":"history/records/2026/07/LK-20260716-source-adjacent-video-autosave.html","kind":"history","section":"history","keywords":"LK-20260716-source-adjacent-video-autosave 2026-07-16 69 fix compatible labkit.ui labkit_VideoMarker_app Runtime V2 project recovery Video Marker autosave location","text":"Source-adjacent Video Marker autosave id: LK-20260716-source-adjacent-video-autosave date: 2026-07-16 sequence: 69 type: fix compatibility: compatible component: `labkit.ui` | `6.0.3 -> 6.0.4` component: `labkit_VideoMarker_app` | `1.4.0 -> 1.4.1` scope: Runtime V2 project recovery scope: Video Marker autosave location Context The first explicit Runtime V2 autosave action wrote only the framework's hidden recovery generation. Video Marker already had a product contract for a visible, stable autosave beside the source video, and users select those MAT files directly in downstream workflows such as Gait Analysis. Decision and rationale Keep generic debounced recovery framework-owned, but let an app provide a deterministic autosave destination when that location is part of its workflow. Video Marker derives the destination from the source video and never asks the user to choose it. Changes Added `services.project.saveAutosave(state,filepath)` without changing named project ownership or dirty status. Restored the visible `Video Marker Autosaves` folder and stable `