diff --git a/.github/workflows/desktop-candidate.yml b/.github/workflows/desktop-candidate.yml new file mode 100644 index 0000000..eb51930 --- /dev/null +++ b/.github/workflows/desktop-candidate.yml @@ -0,0 +1,119 @@ +name: Rieke OS desktop candidate +on: + push: + tags: ['v*'] + workflow_dispatch: + inputs: + tag: + description: Exact reviewed version tag in Rieke-OS + required: true + signed: + description: Require Developer ID signing and notarization + type: boolean + default: false +permissions: + contents: read +concurrency: + group: rieke-desktop-candidate-${{ inputs.tag || github.ref_name }} + cancel-in-progress: false +jobs: + build: + if: github.repository == 'maxwellsdm1867/Rieke-OS' + runs-on: macos-15 + environment: ${{ (github.event_name == 'push' || inputs.signed) && 'desktop-signing' || 'desktop-build' }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref }} + fetch-depth: 0 + - uses: actions/setup-node@v4 + with: + node-version: '22.12.0' + - uses: astral-sh/setup-uv@v6 + - name: Verify clean canonical source and coordinated versions + env: + RELEASE_TAG: ${{ inputs.tag || github.ref_name }} + RELEASE_REPOSITORY: ${{ github.repository }} + run: | + test "$(uname -m)" = arm64 + python3 tools/desktop_release.py baseline --tag "$RELEASE_TAG" --repository "$RELEASE_REPOSITORY" --output "$RUNNER_TEMP/desktop-baseline.json" + - run: npm ci && npm test && npm run build + working-directory: workspace-app + - run: npm ci && npm test + working-directory: desktop + - name: Assemble the complete portable runtime + run: python3 tools/desktop_build_runtime.py --skip-frontend + - name: Verify backend and runtime contracts + run: | + desktop/build/runtime/python/bin/python3.11 -m unittest discover -s python/tests -p 'test_*desktop*.py' -v + desktop/build/runtime/python/bin/python3.11 -m unittest discover -s python/tests -p test_workspace_bootstrap.py -v + python3 tools/desktop_runtime_manifest.py + env: + PYTHONPATH: python + PYTHONDONTWRITEBYTECODE: '1' + - name: Build unsigned local qualification candidate + if: github.event_name != 'push' && !inputs.signed + working-directory: desktop + env: + CSC_IDENTITY_AUTO_DISCOVERY: 'false' + run: npm run dist + - name: Build signed and notarized candidate + if: github.event_name == 'push' || inputs.signed + working-directory: desktop + env: + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + CSC_IDENTITY_AUTO_DISCOVERY: 'false' + run: | + node -e "if(require('./distribution.json').channel!=='signed')throw new Error('Commit the reviewed signed distribution policy before building a signed release')" + test -n "$CSC_LINK" + test -n "$CSC_KEY_PASSWORD" + test -n "$APPLE_API_KEY" + test -n "$APPLE_API_KEY_ID" + test -n "$APPLE_API_ISSUER" + npm run dist + codesign --verify --deep --strict 'dist/mac-arm64/Rieke OS.app' + spctl --assess --type execute 'dist/mac-arm64/Rieke OS.app' + xcrun stapler validate 'dist/mac-arm64/Rieke OS.app' + - name: Exercise updater transport failures without installing + run: npm run test:e2e:updater --prefix desktop + - name: Exercise the actual packaged desktop UI and orderly lifecycle + run: npm run test:e2e --prefix desktop + - name: Exercise explicit unsigned Install and Open + if: github.event_name != 'push' && !inputs.signed + run: npm run test:e2e:bootstrap --prefix desktop + - name: Verify recovery before opening projects when backend startup fails + run: npm run test:e2e:startup-failure --prefix desktop + - name: Audit extracted installers and native database workflows + run: python3 tools/desktop_artifact_e2e.py --installed 'desktop/dist/mac-arm64/Rieke OS.app' --output docs/dev/desktop-artifact-e2e.json + - name: Inventory exact candidate bytes + run: | + python3 tools/desktop_release.py inventory --output desktop/dist/artifacts.json + cp "$RUNNER_TEMP/desktop-baseline.json" desktop/dist/desktop-baseline.json + cp desktop/build/runtime/runtime-audit.json desktop/dist/runtime-audit.json + - uses: actions/upload-artifact@v4 + if: always() + with: + name: desktop-e2e-evidence + path: | + docs/dev/desktop-updater-client-e2e.json + docs/dev/desktop-ui-e2e/ + docs/dev/desktop-artifact-e2e.json + if-no-files-found: warn + retention-days: 30 + - uses: actions/upload-artifact@v4 + with: + name: rieke-desktop-macos-arm64 + path: | + desktop/dist/*.dmg + desktop/dist/*.zip + desktop/dist/*.blockmap + desktop/dist/latest-mac.yml + desktop/dist/artifacts.json + desktop/dist/desktop-baseline.json + desktop/dist/runtime-audit.json + if-no-files-found: error + retention-days: 30 diff --git a/.github/workflows/desktop-promote.yml b/.github/workflows/desktop-promote.yml new file mode 100644 index 0000000..c53b72f --- /dev/null +++ b/.github/workflows/desktop-promote.yml @@ -0,0 +1,69 @@ +name: Promote qualified Rieke OS desktop +on: + workflow_dispatch: + inputs: + tag: + description: Reviewed stable tag + required: true + candidate_run_id: + description: Successful desktop-candidate run containing the exact qualified artifacts + required: true + evidence_path: + description: Reviewed qualification JSON committed to the default branch + required: true +permissions: + contents: read + actions: read +concurrency: + # All stable versions share a lock; an older build cannot race a newer promotion. + group: rieke-desktop-stable-promotion + cancel-in-progress: false +jobs: + promote: + if: github.repository == 'maxwellsdm1867/Rieke-OS' + runs-on: macos-15 + # Repository owners must enable required reviewers here. YAML alone does not. + environment: desktop-publishing + permissions: + contents: write + actions: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22.12.0' + - run: npm ci --ignore-scripts + working-directory: desktop + - name: Require a successful canonical candidate run + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CANDIDATE_RUN: ${{ inputs.candidate_run_id }} + run: | + python3 - <<'PY' + import json, os, re, subprocess + run_id = os.environ['CANDIDATE_RUN'] + if not re.fullmatch(r'\d+', run_id): raise SystemExit('Invalid candidate run ID') + receipt = json.loads(subprocess.check_output(['gh','api',f'repos/maxwellsdm1867/Rieke-OS/actions/runs/{run_id}'],text=True)) + if receipt['conclusion'] != 'success' or receipt['path'] != '.github/workflows/desktop-candidate.yml': + raise SystemExit('Candidate must be a successful desktop build') + PY + - uses: actions/download-artifact@v4 + with: + name: rieke-desktop-macos-arm64 + run-id: ${{ inputs.candidate_run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + path: desktop/dist + - name: Verify reviewed evidence, recover draft uploads, and promote exact bytes + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ inputs.tag }} + EVIDENCE_PATH: ${{ inputs.evidence_path }} + run: | + python3 - <<'PY' + import os, pathlib, subprocess + root = pathlib.Path.cwd().resolve() + evidence = (root / os.environ['EVIDENCE_PATH']).resolve(strict=True) + if not evidence.is_relative_to(root / 'release-evidence') or evidence.suffix != '.json': + raise SystemExit('Evidence must be a reviewed release-evidence JSON in this checkout') + subprocess.run(['python3','tools/desktop_release.py','promote','--tag',os.environ['RELEASE_TAG'],'--evidence',str(evidence)],check=True) + PY diff --git a/.github/workflows/workspace-release-candidate.yml b/.github/workflows/workspace-release-candidate.yml index 1bda0ea..f9d8f9d 100644 --- a/.github/workflows/workspace-release-candidate.yml +++ b/.github/workflows/workspace-release-candidate.yml @@ -1,12 +1,19 @@ -name: Build signed Rieke OS release candidate +name: Legacy source-release candidate (manual) on: workflow_dispatch: inputs: tag: description: Reviewed stable version tag, for example v0.1.0 required: true + publish: + description: Publish the validated candidate as the latest stable GitHub Release + type: boolean + default: false permissions: contents: read +concurrency: + group: rieke-release-${{ inputs.tag || github.ref_name }} + cancel-in-progress: false jobs: candidate: # First advertised platform only. Linux needs its own native validation. @@ -15,7 +22,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.tag }} + ref: ${{ inputs.tag || github.ref }} fetch-depth: 0 - uses: actions/setup-node@v4 with: @@ -58,5 +65,26 @@ jobs: name: signed-rieke-release-candidate path: ${{ runner.temp }}/rieke-candidate/ if-no-files-found: error - # Deliberately no public release publication. Promotion requires the real - # database, transfer, old-to-new upgrade and licensed MATLAB gates in docs. + publish: + needs: candidate + if: github.repository == 'maxwellsdm1867/Rieke-OS' && (github.event_name == 'push' || inputs.publish) + runs-on: ubuntu-latest + # Configure required reviewers here to attest the real upgrade/recovery and + # worker-shutdown evidence in docs/dev/releasing-rieke-os.md before promotion. + environment: release-publishing + permissions: + contents: write + steps: + - uses: actions/download-artifact@v4 + with: + name: signed-rieke-release-candidate + path: ${{ runner.temp }}/rieke-candidate + - name: Publish the exact signed candidate + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + RELEASE_TAG: ${{ inputs.tag || github.ref_name }} + CANDIDATE_DIRECTORY: ${{ runner.temp }}/rieke-candidate + run: | + gh release create "$RELEASE_TAG" "$CANDIDATE_DIRECTORY"/* \ + --verify-tag --latest=false --generate-notes --title "Rieke OS source $RELEASE_TAG" diff --git a/.gitignore b/.gitignore index 562c5ea..45274f2 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,9 @@ docs/legacy/old_epochtree/ # Clone-local Rieke OS dependencies/config (never scientific project data) /.rieke-runtime/ + +# Desktop build closure and local packages (source/locks remain tracked) +/desktop/node_modules/ +/desktop/build/ +/desktop/dist/ +/desktop/resources/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e5826..2123aec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Rieke OS [0.1.3] - 2026-09-30 + +This desktop candidate uses the explicit unsigned testing channel. It is separate +from the MATLAB library version below and from signed production distribution. + +### Added +- Self-contained Apple Silicon desktop packaging with private Python and MySQL runtimes, folder selection, controlled installation, and testing-channel updates. +- Persistent native tag membership and autocomplete dictionaries, with Unicode prefix indexes, maintained usage counts, and exact author attribution. +- Transactional annotation history, incremental current-state recovery, and verified index migration and reuse. + +### Improved +- Small annotation batches acknowledge durable saves promptly; cell tags inherit by cell UUID without copying annotations into every epoch. +- Large-project browsing, selection, metadata storage, cache validation, and protocol-scoped curation preserve exact scientific identities. +- Portable project handling, folder-boundary checks, draft preservation, and desktop service lifecycle validation. + +At 100,000 synthetic epochs, tag autocomplete measured 21–26 ms. Initial native +index preparation took about two minutes; the paired two-save/filter API sequence +measured 192 ms. See the [reproducible benchmark report](docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.md) +for scope, first-use measurements, and limitations. + ## [1.0.0] - 2026-02-28 ### Added diff --git a/CONTEXT.md b/CONTEXT.md index 8bb0866..db82380 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -28,6 +28,34 @@ _Avoid_: Matching cells solely by a repeated label such as Cell2 Recording date plus original cell name/number, with a separate cell-type tag; include a session qualifier when labels collide. Stable cell UUIDs are available as details. _Avoid_: Using a mutable cell-type classification as a database key +**Recorded cell identity**: +The identity of a cell in an acquisition, together with its recorded source and experimental ancestry. Matching dates, labels, classifications or measured values do not establish that two records identify the same cell. +_Avoid_: Cell number as identity, identity inferred from matching metadata + +**Cell correspondence**: +A reviewed scientific claim that distinct recorded cell identities refer to the same biological cell, supported by retained evidence and provenance. +_Avoid_: Automatic merge, renaming a cell to resolve uncertain identity + +**Source revision**: +One exact version of a recording's original contents. Moving or renaming an unchanged recording does not create a new source revision; changing its contents does. +_Avoid_: Filename as identity + +**Identity conflict**: +Evidence that a recorded identifier, its ancestry, or its source revision disagrees with another representation of the same acquisition. A conflict is distinct from two legitimate acquisitions sharing a display label. +_Avoid_: Duplicate inferred from name, overwriting to reconcile + +**Shared tag**: +A project annotation attached to an exact cell or epoch identity, with its author profile and provenance retained across protocol workspaces. +_Avoid_: A dataset-specific inclusion decision, an acquisition identifier + +**Inherited cell tag**: +A cell annotation visible on its epochs through their recorded cell UUID relationship. Inheritance does not copy or reassign the annotation to each epoch. +_Avoid_: Inheritance by matching cell labels or dates + +**Dataset tag**: +A curation tag scoped to an epoch within a particular protocol workspace. Multiple dataset tags and shared tags may coexist without changing acquisition identity. +_Avoid_: Treating all tags as one unscoped set + **Recorded duration**: The sum of recording durations for distinct epochs in an explicit scope and timebase, counting an epoch once across its streams and excluding gaps. _Avoid_: Session elapsed time, stimulation time, summing the same epoch once per device diff --git a/desktop/.gitignore b/desktop/.gitignore new file mode 100644 index 0000000..1096628 --- /dev/null +++ b/desktop/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +dist/ +resources/ +build-work/ +build/ diff --git a/desktop/README.md b/desktop/README.md new file mode 100644 index 0000000..162c99a --- /dev/null +++ b/desktop/README.md @@ -0,0 +1,166 @@ +# Rieke OS desktop + +This package contains the Electron shell for the existing scientific React app. +The first implementation targets macOS Apple Silicon. Its complete resource +closure currently requires a macOS 14.0 floor; support on that minimum still +needs real-device qualification. Other platforms are not advertised. The optional +debugpy PID attachment helper is excluded with provenance in the runtime receipt. + +Native signing applies the existing `allow-jit` entitlement only to the bundled +Python executable. The signed scientific and JIT workflow remains unqualified +without Developer ID credentials and independent final-artifact evidence. + +## Local build + +Building requires Node/npm, Python 3.11 or newer for build tools, uv, the macOS +developer toolchain and network access. Running the assembled app uses only its +bundled interpreter, parser, MySQL and frontend. It never provisions dependencies +at launch. + +The desktop app requires no Docker CLI, Docker Desktop or Docker daemon. Each +desktop project uses the native MySQL executable inside the app bundle, with its +database files outside the bundle in the project folder. Opening, creating, +importing, querying, exporting and reopening desktop projects work independently +of Docker. + +An older project can still have its only database inside the previous source +installation's Docker container. Reading that existing database is a one-time +source migration option, not a desktop runtime requirement. Receive a portable +transfer prepared by the source installation instead when Docker is unavailable +on the destination. A completed desktop copy uses the bundled native database. + +```sh +npm ci --prefix workspace-app +npm ci --prefix desktop +python3 tools/desktop_build_runtime.py +npm test --prefix desktop +python3 tools/desktop_runtime_manifest.py +CSC_IDENTITY_AUTO_DISCOVERY=false npm run dist --prefix desktop +``` + +The artifacts are in `desktop/dist`, including the complete +`mac-arm64/Rieke OS.app`, DMG, updater ZIP, blockmaps and `latest-mac.yml`. +Build caches and artifacts are ignored by Git. Parser and native dependency pins, +license inventory, source provenance and resource hashes are carried inside the +runtime; recordings, scientific projects and credentials are excluded. + +For development against the assembled runtime, run `npm start --prefix desktop`. +For local icon-based testing, place the complete unsigned app at +`~/Applications/Rieke OS.app` without overwriting an existing installation. +The complete app at that fixed location runs independently of the checkout. +This build explicitly selects the `unsigned-testing` distribution. Its Install +and Open action verifies the complete app and installs a user-owned copy while +preserving macOS quarantine. Its GitHub checks show newer testing versions; +downloads and restart/install require the user's action. Ordinary Quit never +installs a testing update. See [the testing release workflow](../docs/dev/GITHUB_TESTING_RELEASE.md). + +The default signed distribution still requires Developer ID verification for +installation and updates. Unsigned testing does not qualify that production path. + +## Packaged end-to-end tests + +After building, run the actual packaged UI and failure suites: + +```sh +npm run test:e2e --prefix desktop +npm run test:e2e:startup-failure --prefix desktop +npm run test:e2e:updater --prefix desktop +``` + +The UI suite copies the complete packaged app into a fresh temporary HOME, uses +an isolated Electron user-data directory and creates disposable native projects. +It tests the real sandboxed React UI, durable saved views, project navigation, +duplicate launches, renderer recovery and orderly shutdown. Only native folder +chooser return values are stubbed. Set `RIEKE_E2E_H5` to a read-only source fixture +to also test real import activity and native close deferral; the suite copies it +before import, and CI runs without private recordings. The startup-failure suite +changes and reseals only its disposable app copy to test failed backend readiness. +These tests never open or close the user's installed app. If orderly shutdown +fails, the test preserves its isolated processes for investigation. + +For an explicit no-Docker recording workflow check, run: + +```sh +python3 tools/desktop_no_docker_smoke.py --recording /path/to/test-recording.h5 +``` + +This uses the packaged runtime with a fresh HOME and restricted PATH. It denies +container commands and non-MySQL Unix sockets before access, tests those denials +with separate negative controls, and then exercises native project creation, +recording import, tags, query, export, reopen and orderly shutdown. The source +recording is copied for import; the host Docker daemon and installed app are +untouched. This is process-level test instrumentation, not a kernel sandbox or +clean-machine qualification. + +Receipts and screenshots go to `docs/dev/desktop-ui-e2e/`. The updater suite uses +the pinned real client with local HTTP transport faults. These unsigned local +tests do not qualify signed installation or signed old-to-new recovery. + +## Ownership and shutdown + +The Electron main process owns the private authenticated production Waitress +backend and all project services. A private child-pipe binding receipt precedes +the first authenticated HTTP request. The renderer is sandboxed, has no Node +integration and uses narrow validated top-frame IPC. Main injects per-session +headers only into verified owned origins; Python source update APIs are disabled +for desktop services. + +Renderer drafts and outstanding preference writes must acknowledge persistence +before backend drain. Imports, inbox work, transfers, streaming responses and +other active writes defer closure. Every owned project/database service and the +root backend must acknowledge actual exit. Timeouts and crashes do not authorize +process termination or app replacement. + +An older failed launcher can retain its idle root after rejecting a legacy +project. If recovery refuses Quit, preserve the installed bundle and service +registry for an ownership review. A controlled shutdown must first verify the +exact owned processes and confirm that no project service, database, import or +other writer is active; app replacement continues to refuse a live prior root. +Deleting registry files cannot establish that shutdown. The new launcher offers +legacy migration into a separate verified copy while preserving the source +project and its existing source application. This work's isolated tests leave +the user's older running installation unchanged. + +## Signed releases + +The public provider is explicitly `maxwellsdm1867/Rieke-OS`. Application, +frontend, and desktop metadata are coordinated at version 0.1.3. The current +`unsigned-testing` policy uses the separate `desktop-test-v0.1.3` prerelease; +it does not promote or replace the stable source release. Build from the exact +clean canonical source commit and qualify the resulting bytes before publishing. +`tools/desktop_release.py` separately rejects dirty, mismatched or foreign signed +production baselines and incomplete promotion. + +The desktop candidate workflow builds exact tagged sources. Signing is performed +on the native closure before resealing the runtime manifest and signing the outer +bundle. Notarization follows. Configure protected `desktop-signing` secrets +`CSC_LINK`, `CSC_KEY_PASSWORD`, `APPLE_API_KEY`, `APPLE_API_KEY_ID` and +`APPLE_API_ISSUER`; no credentials are included in the app. Configure required +reviewers for `desktop-publishing` in GitHub settings; YAML does not enable them. + +Promotion takes an existing successful candidate run and reviewed qualification +JSON from `release-evidence/` on the default branch. Evidence uses format +`rieke-desktop-qualification`, version 1, exact application/source/platform +identity, the artifact inventory from `artifacts.json`, and an entry for every +R01–R12 requirement. Each entry requires `passed: true` and `receipts` containing +a description and SHA-256 of the real-artifact evidence. Unit-test counts do not +substitute for qualification. Use confidential-source-free receipts. + +Promotion is serialized across versions. Existing release bytes cannot be +overwritten on retry. A complete draft becomes public without changing latest; +all public asset hashes are checked without authentication before stable/latest +is changed. An unsigned candidate must never be supplied as qualified evidence. +The legacy source-release workflow is manual and does not promote itself latest. + +Updates download quietly, are checked about hourly with jitter and require exact +signature, version, platform, resource and data-format validation. A signed prior +app is retained before installation. Ready means those candidate checks passed; +native staging and startup health are separate. Only the coordinator invokes the +native installer after draft/drain acknowledgements. Recovery verifies the +retained signer and data contract and uses the same controlled installation code. + +The production specification remains the acceptance authority: +[electron-production-spec.md](../docs/design/electron-production-spec.md). +Signing, notarization, clean-machine installation, source-user migration, full +fault-injection qualification and a real signed old-to-new update remain gates +until independently demonstrated with the final artifacts. diff --git a/desktop/bootstrap.cjs b/desktop/bootstrap.cjs new file mode 100644 index 0000000..bc8af7a --- /dev/null +++ b/desktop/bootstrap.cjs @@ -0,0 +1,174 @@ +'use strict'; +const fs = require('./physical-fs.cjs').promises; +const path = require('node:path'); +const os = require('node:os'); +const {execFile} = require('node:child_process'); +const {promisify} = require('node:util'); +const {randomUUID, createHash} = require('node:crypto'); +const runFile = promisify(execFile); +const {verifyResources, compareVersions, stableVersion, compatibleMacMinimum} = require('./updater-validation.cjs'); +const APP_ID = 'org.riekeos.desktop'; +function enclosingApp(executable) { + const marker = `${path.sep}Contents${path.sep}MacOS${path.sep}`; + const index = executable.lastIndexOf(marker); + return index >= 0 ? executable.slice(0, index) : null; +} +async function signatureIdentity(bundle, run = runFile) { + await run('/usr/bin/codesign', ['--verify', '--deep', '--strict', bundle]); + const details = await run('/usr/bin/codesign', ['--display', '--verbose=4', bundle]); + const text = `${details.stdout}\n${details.stderr}`; + const identifier = /^Identifier=(.+)$/m.exec(text)?.[1]; + const team = /^TeamIdentifier=(.+)$/m.exec(text)?.[1]; + if (identifier !== APP_ID || !team || team === 'not set' || !/^Authority=Developer ID Application:/m.test(text)) + throw new Error('Install and Open requires the verified Developer ID signed Rieke OS app'); + return {identifier, team}; +} +async function assertNotRunning(bundle, run = runFile, ignorePid = null) { + const {stdout} = await run('/bin/ps', ['-axo', 'pid=,comm=']); + const prefix = `${bundle}${path.sep}`; + if (stdout.split('\n').some(line => { + const match = /^\s*(\d+)\s+(.+)$/.exec(line); + return match && Number(match[1]) !== ignorePid && match[2].startsWith(prefix); + })) + throw new Error('The installed Rieke OS app is running. Quit it before installation.'); +} +async function readBundleManifest(bundle) { + return JSON.parse(await fs.readFile(path.join(bundle, 'Contents', 'Resources', 'runtime', 'runtime-manifest.json'), 'utf8')); +} +async function quarantineAttribute(bundle, run) { + try { + const result = await run('/usr/bin/xattr', ['-px', 'com.apple.quarantine', bundle]); + return result.stdout.replace(/\s/g, '').toLowerCase(); + } catch (error) { + if (error.code === 1 && /No such xattr/i.test(error.stderr || '')) return null; + throw error; + } +} +async function bundleDigest(bundle) { + const info = await fs.lstat(bundle); + if (!info.isDirectory() || info.isSymbolicLink()) throw new Error('A regular complete application bundle is required'); + const root = await fs.realpath(bundle), records = []; + let bytes = 0; + async function visit(directory) { + for (const name of (await fs.readdir(directory)).sort()) { + const file = path.join(directory, name), stat = await fs.lstat(file); + const relative = path.relative(root, file).split(path.sep).join('/'); + if (records.length >= 120000) throw new Error('Application bundle exceeds inventory bounds'); + const record = {path: relative, mode: stat.mode & 0o777}; + if (stat.isSymbolicLink()) { + const target = await fs.readlink(file), physical = await fs.realpath(file); + if (path.isAbsolute(target) || (!physical.startsWith(root + path.sep) && physical !== root)) throw new Error('Application symlink escapes its bundle'); + records.push({...record, type: 'symlink', target}); + } else if (stat.isDirectory()) { + records.push({...record, type: 'directory'}); await visit(file); + } else if (stat.isFile()) { + bytes += stat.size; + if (bytes > 8 * 1024 ** 3) throw new Error('Application bundle exceeds size bounds'); + const digest = createHash('sha256'), handle = await fs.open(file, 'r'); + try { for await (const chunk of handle.createReadStream()) digest.update(chunk); } finally { await handle.close(); } + records.push({...record, type: 'file', size: stat.size, sha256: digest.digest('hex')}); + } else throw new Error('Application contains a special file'); + } + } + await visit(root); + return createHash('sha256').update(JSON.stringify(records)).digest('hex'); +} +function testingDistribution(distribution) { + if (distribution === undefined || distribution === null || distribution.channel === 'signed') return false; + if (distribution.channel !== 'unsigned-testing') throw new Error('Unsupported application distribution policy'); + return true; +} +async function bundleIdentity(bundle, distribution, run, {verifyTestingSeal = true} = {}) { + if (!testingDistribution(distribution)) return signatureIdentity(bundle, run); + if (verifyTestingSeal) await run('/usr/bin/codesign', ['--verify', '--deep', '--strict', bundle]); + const plist = path.join(bundle, 'Contents', 'Info.plist'); + const declared = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleIdentifier', plist]); + if (declared.stdout.trim() !== APP_ID) throw new Error('Unsigned testing app identifier differs'); + const executable = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleExecutable', plist]); + if (executable.stdout.trim() !== 'Rieke OS' || !(await fs.stat(path.join(bundle, 'Contents', 'MacOS', 'Rieke OS'))).isFile()) throw new Error('Unsigned testing app executable is missing'); + return {identifier: APP_ID, team: null, channel: 'unsigned-testing'}; +} +async function verifyTestingBundle(bundle, run = runFile) { + await bundleIdentity(bundle, {channel: 'unsigned-testing'}, run); + const manifest = await readBundleManifest(bundle); + const required = ['python/bin/python3.11', 'mysql/bin/mysqld', 'mysql/bin/mysql', 'mysql/bin/mysqldump', 'application/python/workspace_desktop.py']; + if (!compatibleManifest(manifest, manifest) || !/^[a-f0-9]{40}$/.test(manifest.source_commit || '') || !/^[a-f0-9]{40}$/.test(manifest.parser_commit || '') || + !/^3\.11\.\d+$/.test(manifest.python_version || '') || !/^8\.4\.\d+$/.test(manifest.mysql_version || '') || !Array.isArray(manifest.workspace_formats) || !manifest.workspace_formats.length || + !Number.isInteger(manifest.database_compatibility) || !required.every(name => manifest.resources?.[name])) throw new Error('Unsigned testing runtime closure is incomplete'); + stableVersion(manifest.application_version); + const plist = path.join(bundle, 'Contents', 'Info.plist'); + const version = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleShortVersionString', plist]); + const minimum = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :LSMinimumSystemVersion', plist]); + if (version.stdout.trim() !== manifest.application_version || minimum.stdout.trim() !== manifest.minimum_macos_version) throw new Error('Unsigned testing app and runtime versions differ'); + const host = await run('/usr/bin/sw_vers', ['-productVersion']); + compatibleMacMinimum(manifest.minimum_macos_version, host.stdout.trim()); + return manifest; +} +function compatibleManifest(candidate, current) { + return candidate.format === 'rieke-desktop-runtime' && candidate.version === 1 && candidate.platform === 'darwin' && candidate.architecture === 'arm64' && + candidate.mysql_version === current.mysql_version && + candidate.database_compatibility === current.database_compatibility && + JSON.stringify(candidate.workspace_formats) === JSON.stringify(current.workspace_formats); +} +async function installCompleteBundle({source, destination = path.join(os.homedir(), 'Applications', 'Rieke OS.app'), run = runFile, allowRollback = false, ignorePid = null, distribution, expectedBundleSha256}) { + const unsignedTesting = testingDistribution(distribution); + if (ignorePid !== null && (!allowRollback || ignorePid !== process.pid)) throw new Error('Only the dedicated current recovery helper may be exempted from running-app checks'); + if (!source || !source.endsWith('.app')) throw new Error('A complete app bundle is required'); + const parent = path.dirname(destination); + await fs.mkdir(parent, {recursive: true, mode: 0o700}); + const info = await fs.lstat(parent); + if (info.isSymbolicLink() || info.uid !== process.getuid()) throw new Error('Installation folder must be owned by the current user'); + const sourceDigest = unsignedTesting ? await bundleDigest(source) : null; + const quarantine = unsignedTesting ? await quarantineAttribute(source, run) : null; + if (expectedBundleSha256 !== undefined && sourceDigest !== expectedBundleSha256) throw new Error('Downloaded application bundle checksum differs'); + const sourceIdentity = await bundleIdentity(source, distribution, run); + const sourceManifest = await readBundleManifest(source); + if (unsignedTesting) await verifyTestingBundle(source, run); + stableVersion(sourceManifest.application_version); + if (!compatibleManifest(sourceManifest, sourceManifest) || !sourceManifest.source_commit || !sourceManifest.resources || + !Array.isArray(sourceManifest.workspace_formats) || !Number.isInteger(sourceManifest.database_compatibility)) + throw new Error('Downloaded app runtime manifest is invalid'); + const sourcePlist = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleShortVersionString', path.join(source, 'Contents', 'Info.plist')]); + if (sourcePlist.stdout.trim() !== sourceManifest.application_version) throw new Error('App and runtime versions differ'); + await verifyResources(path.join(source, 'Contents', 'Resources', 'runtime'), sourceManifest.resources); + const lock = path.join(parent, '.rieke-os-install.lock'); + await fs.mkdir(lock, {mode: 0o700}); + const staging = path.join(parent, `.Rieke OS.install-${randomUUID()}.app`); + const previous = path.join(parent, '.Rieke OS.previous.app'); + let movedPrevious = false; + try { + let existing = false; + try { + const targetInfo = await fs.lstat(destination); + if (targetInfo.isSymbolicLink() || targetInfo.uid !== process.getuid()) throw new Error('Installed app is not a user-owned bundle'); + const installedIdentity = await bundleIdentity(destination, distribution, run, {verifyTestingSeal: false}); + if (installedIdentity.team !== sourceIdentity.team) throw new Error('Installed app has a different signing identity'); + const installedManifest = await readBundleManifest(destination); + if (!compatibleManifest(sourceManifest, installedManifest)) throw new Error('Installed app uses incompatible workspace or database formats'); + if (!allowRollback && compareVersions(sourceManifest.application_version, installedManifest.application_version) < 0) throw new Error('Install and Open cannot downgrade the installed app'); + await verifyResources(path.join(destination, 'Contents', 'Resources', 'runtime'), installedManifest.resources); + await assertNotRunning(destination, run, ignorePid); existing = true; + } catch (error) { if (error.code !== 'ENOENT') throw error; } + await run('/usr/bin/ditto', ['--rsrc', '--extattr', '--acl', source, staging]); + const copiedIdentity = await bundleIdentity(staging, distribution, run); + if (copiedIdentity.team !== sourceIdentity.team) throw new Error('Copied app signature differs from downloaded app'); + await verifyResources(path.join(staging, 'Contents', 'Resources', 'runtime'), sourceManifest.resources); + if (unsignedTesting && await bundleDigest(staging) !== sourceDigest) throw new Error('Copied application bundle checksum differs'); + if (unsignedTesting && await quarantineAttribute(staging, run) !== quarantine) throw new Error('Copied application quarantine attribute differs'); + if (!unsignedTesting) await run('/usr/sbin/spctl', ['--assess', '--type', 'execute', staging]); + if (existing) { + await assertNotRunning(destination, run, ignorePid); + // Retain exactly one verified previous signed bundle, only after the new copy is complete. + await fs.rm(previous, {recursive: true, force: true}); + await fs.rename(destination, previous); movedPrevious = true; + } + try { await fs.rename(staging, destination); } + catch (error) { if (movedPrevious) await fs.rename(previous, destination); throw error; } + await bundleIdentity(destination, distribution, run); + return {destination, previous: movedPrevious ? previous : null}; + } finally { + await fs.rm(staging, {recursive: true, force: true}); + await fs.rm(lock, {recursive: true, force: true}); + } +} +module.exports = {APP_ID, enclosingApp, signatureIdentity, assertNotRunning, compatibleManifest, installCompleteBundle, readBundleManifest, bundleDigest, verifyTestingBundle}; diff --git a/desktop/distribution.cjs b/desktop/distribution.cjs new file mode 100644 index 0000000..e15f340 --- /dev/null +++ b/desktop/distribution.cjs @@ -0,0 +1,10 @@ +'use strict'; +const REPOSITORY = 'maxwellsdm1867/Rieke-OS'; +function distributionPolicy(value) { + if (value === undefined) return Object.freeze({channel:'signed',repository:REPOSITORY}); + if (value?.format !== 'rieke-desktop-distribution' || value.version !== 1 || + !['signed','unsigned-testing'].includes(value.channel) || value.repository !== REPOSITORY) + throw new Error('The desktop distribution policy is invalid.'); + return Object.freeze({...value}); +} +module.exports={distributionPolicy}; diff --git a/desktop/distribution.json b/desktop/distribution.json new file mode 100644 index 0000000..a893a0b --- /dev/null +++ b/desktop/distribution.json @@ -0,0 +1,6 @@ +{ + "format": "rieke-desktop-distribution", + "version": 1, + "channel": "unsigned-testing", + "repository": "maxwellsdm1867/Rieke-OS" +} diff --git a/desktop/draft-barrier.cjs b/desktop/draft-barrier.cjs new file mode 100644 index 0000000..096b198 --- /dev/null +++ b/desktop/draft-barrier.cjs @@ -0,0 +1,26 @@ +'use strict'; +const {randomUUID} = require('node:crypto'); +class DraftBarrier { + constructor({timeout = 10000, send = (window, value) => window.webContents.send('desktop:prepare-close', value)} = {}) { + this.timeout = timeout; this.send = send; this.pending = new Map(); + } + acknowledge(payload, window) { + if (!payload || typeof payload.requestId !== 'string' || typeof payload.ok !== 'boolean' || Object.keys(payload).sort().join(',') !== 'ok,requestId') throw new TypeError('Invalid draft acknowledgement'); + const pending = this.pending.get(payload.requestId); + if (!pending || pending.window !== window) throw new Error('No matching draft request'); + pending.resolve(payload.ok); return {acknowledged: true}; + } + async prepare(windows) { + if ([...windows].some(window => window.isDestroyed() || window.draftUnavailable)) + return {ready: false, reason: 'Renderer drafts have not been acknowledged. Restore the scientific window before quitting.'}; + const results = await Promise.all([...windows].map(window => new Promise(resolve => { + const requestId = randomUUID(); + const finish = ok => { clearTimeout(timer); this.pending.delete(requestId); resolve(ok); }; + const timer = setTimeout(() => finish(false), this.timeout); + this.pending.set(requestId, {window, resolve: finish}); + try { this.send(window, {requestId}); } catch { finish(false); } + }))); + return results.every(Boolean) ? {ready: true} : {ready: false, reason: 'Draft persistence was not acknowledged; quit and replacement are deferred'}; + } +} +module.exports = {DraftBarrier}; diff --git a/desktop/draft-store.cjs b/desktop/draft-store.cjs new file mode 100644 index 0000000..b992331 --- /dev/null +++ b/desktop/draft-store.cjs @@ -0,0 +1,55 @@ +'use strict'; +const fs = require('node:fs/promises'); +const path = require('node:path'); +const {randomUUID} = require('node:crypto'); +const {validateDraft, validateProjectId} = require('./security.cjs'); +const MAX_DRAFT_BYTES = 2 * 1024 * 1024; +function validStoredDraft(value, projectId) { + return value !== null && typeof value === 'object' && !Array.isArray(value) && + value.format === 'rieke-renderer-draft' && value.version === 1 && value.projectId === projectId && + value.value !== null && typeof value.value === 'object' && !Array.isArray(value.value); +} +class DraftStore { + constructor(userData) { this.userData = userData; this.directory = path.join(userData, 'drafts'); this.pending = new Set(); } + async location(projectId) { + const id = validateProjectId(projectId); + await fs.mkdir(this.directory, {recursive: true, mode: 0o700}); + const stat = await fs.lstat(this.directory); + if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid()) throw new Error('Draft state directory is redirected or not privately owned'); + return {id, filename: path.join(this.directory, `${id}.json`)}; + } + recovery(id) { this.pending.add(id); return {format: 'rieke-draft-recovery', version: 1, projectId: id, reason: 'saved-draft-unreadable'}; } + async load(projectId) { + const id = validateProjectId(projectId); + if (this.pending.has(id)) return this.recovery(id); + let filename; + try { ({filename} = await this.location(id)); } + catch { return this.recovery(id); } + try { + const stat = await fs.lstat(filename); + if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_DRAFT_BYTES || stat.uid !== process.getuid()) return this.recovery(id); + const value = JSON.parse(await fs.readFile(filename, 'utf8')); + return validStoredDraft(value, id) ? value : this.recovery(id); + } catch (error) { return error.code === 'ENOENT' ? null : this.recovery(id); } + } + async save(payload) { + const {projectId, serialized} = validateDraft(payload); + if (!validStoredDraft(payload.value, projectId)) throw new TypeError('Invalid renderer draft identity or schema'); + await this.load(projectId); + if (this.pending.has(projectId)) throw new Error('Saved view needs an explicit recovery decision before it can be replaced'); + const {filename} = await this.location(projectId); + const temporary = `${filename}.${randomUUID()}.tmp`; + try { await fs.writeFile(temporary, serialized, {mode: 0o600, flag: 'wx'}); await fs.rename(temporary, filename); } + finally { await fs.rm(temporary, {force: true}); } + return {saved: true}; + } + async reset(projectId) { + const id = validateProjectId(projectId); + if (!this.pending.has(id)) throw new Error('No verified unreadable draft is pending recovery'); + const {filename} = await this.location(id); + try { await fs.rename(filename, path.join(this.directory, `${id}.corrupt-${randomUUID()}.json`)); } + catch (error) { if (error.code !== 'ENOENT') throw error; } + this.pending.delete(id); return {reset: true}; + } +} +module.exports = {DraftStore, validStoredDraft, MAX_DRAFT_BYTES}; diff --git a/desktop/e2e/backend-failure.e2e.cjs b/desktop/e2e/backend-failure.e2e.cjs new file mode 100644 index 0000000..d3ed942 --- /dev/null +++ b/desktop/e2e/backend-failure.e2e.cjs @@ -0,0 +1,41 @@ +'use strict'; +const assert = require('node:assert/strict'); +const fs = require('node:fs/promises'), path = require('node:path'); +const {createHash} = require('node:crypto'); +const {createFixture, launch, run} = require('./helpers.cjs'); +const {resealRuntimeManifest} = require('../sign-runtime.cjs'); +const {verifyResources} = require('../updater-validation.cjs'); +(async () => { + const fixture = await createFixture({reuse: false}); + const runtime = path.join(fixture.bundle, 'Contents/Resources/runtime'); + const sourceManifestSha256 = createHash('sha256').update(await fs.readFile(path.join(runtime, 'runtime-manifest.json'))).digest('hex'); + const appAsarSha256 = createHash('sha256').update(await fs.readFile(path.join(fixture.bundle, 'Contents/Resources/app.asar'))).digest('hex'); + const entry = path.join(runtime, 'application/python/workspace_desktop.py'); + // This faulted copy is disposable and never supplies signing/release evidence. + // The literal statement cannot import project code, bind services or start DB. + const literalFailure = "raise RuntimeError('Injected packaged backend failure before imports, binding, projects or databases')\n"; + await fs.writeFile(entry, literalFailure); + const manifest = await resealRuntimeManifest(runtime); await verifyResources(runtime, manifest.resources); + const {application, page} = await launch(fixture); + await page.getByRole('heading', {name: 'Rieke OS recovery', exact: true}).waitFor({timeout: 90000}); + const status = await page.evaluate(() => window.riekeDesktop.status()); + assert.equal(status.state, 'Recovery'); assert.match(status.detail, /exited before owning its listener/); + assert.equal(await page.getByRole('heading', {name: 'Your projects', exact: true}).count(), 0); + const record = JSON.parse(await fs.readFile(path.join(fixture.userData, 'desktop-service.json'), 'utf8')); + assert.ok(record.executable.startsWith(fixture.bundle + '/')); + await assert.rejects(run('/bin/ps', ['-p', String(record.pid), '-o', 'comm='])); + assert.equal((await page.evaluate(() => window.riekeDesktop.quit())).ready, false); + assert.equal((await fs.readdir(path.join(fixture.userData, 'backend'))).length, 0); + const output = path.resolve(__dirname, '../../docs/dev/desktop-ui-e2e'); await fs.mkdir(output, {recursive: true}); + await page.screenshot({path: path.join(output, 'backend-startup-recovery.png')}); + const receipt = {format: 'rieke-packaged-backend-failure-e2e', version: 1, passed: true, signed_qualification: false, + method: 'Separate disposable packaged clone; literal raise-before-import backend; clone-only manifest reseal', + source_manifest_sha256: sourceManifestSha256, app_asar_sha256: appAsarSha256, + fault_code_sha256: createHash('sha256').update(literalFailure).digest('hex'), recovery_before_projects: true, + backend_exited: true, no_service_or_database_start: true, unsafe_quit_deferred: true, + teardown: 'Only this test GUI exits after the known literal failed backend has exited; no workers or databases existed'}; + await fs.writeFile(path.join(output, 'backend-startup-failure.json'), JSON.stringify(receipt, null, 2) + '\n'); + const exited = new Promise(resolve => application.process().once('exit', resolve)); + await application.evaluate(({app}) => app.exit(0)); assert.equal(await exited, 0); + console.log(JSON.stringify(receipt)); +})().catch(error => {console.error(error.message); process.exitCode = 1;}); diff --git a/desktop/e2e/bootstrap.e2e.cjs b/desktop/e2e/bootstrap.e2e.cjs new file mode 100644 index 0000000..0c30bd1 --- /dev/null +++ b/desktop/e2e/bootstrap.e2e.cjs @@ -0,0 +1,89 @@ +'use strict'; +// Real downloaded app UI, installer copy/seal/quarantine checks and installed +// startup. Only Launch Services dispatch is stubbed in this disposable clone; +// it must never target the user's running application or profile. +const assert=require('node:assert/strict'),fs=require('node:fs/promises'),path=require('node:path'); +const {createHash}=require('node:crypto'); +const {_electron}=require('playwright'); +const asar=require('@electron/asar'); +const {createFixture,launch,gracefulQuit,run}=require('./helpers.cjs'); +const {verifyResources}=require('../updater-validation.cjs'); +const {bundleDigest}=require('../bootstrap.cjs'); +const output=path.resolve(__dirname,'../../docs/dev/desktop-ui-e2e/bootstrap-receipt.json'); +const receipt={format:'rieke-packaged-bootstrap-e2e',version:1,signed_qualification:false,checks:[],failures:[],method:'Real downloaded packaged clone with native install checks; only /usr/bin/open dispatch stubbed; isolated installed profile launched with Playwright'}; +let fixture,application,page; +async function write(){await fs.mkdir(path.dirname(output),{recursive:true});await fs.writeFile(output,JSON.stringify(receipt,null,2)+'\n');} +async function check(name,fn){try{const evidence=await fn();receipt.checks.push({name,passed:true,evidence});console.log('PASS '+name);}catch(error){receipt.failures.push({name,message:error.message});await write();throw error;}await write();} +async function main(){ + fixture=await createFixture({reuse:false});receipt.fixture_root=fixture.root; + const target=fixture.bundle,downloaded=path.join(fixture.home,'Downloads','Rieke OS.app'); + const resources=path.join(target,'Contents/Resources'),sourceAsar=path.join(resources,'app.asar'); + receipt.source_app_asar_sha256=createHash('sha256').update(await fs.readFile(sourceAsar)).digest('hex'); + const manifestBytes=await fs.readFile(path.join(resources,'runtime/runtime-manifest.json')),manifest=JSON.parse(manifestBytes); + receipt.source_manifest_sha256=createHash('sha256').update(manifestBytes).digest('hex');receipt.application_version=manifest.application_version; + await fs.mkdir(path.dirname(downloaded),{recursive:true});await fs.rename(target,downloaded); + fixture.bundle=downloaded;fixture.executable=path.join(downloaded,'Contents/MacOS/Rieke OS'); + const archive=path.join(downloaded,'Contents/Resources/app.asar'),unpacked=path.join(fixture.root,'bootstrap-test-asar'),handoff=path.join(fixture.home,'launch-services-handoff.json'); + asar.extractAll(archive,unpacked); + const mainFile=path.join(unpacked,'main.cjs'),original=await fs.readFile(mainFile,'utf8'); + const exact="const {execFile} = require('node:child_process');"; + assert.ok(original.includes(exact),'Expected packaged main OS process boundary'); + const wrapper=`const nativeExecFile = require('node:child_process').execFile; +const execFile = (...args) => nativeExecFile(...args); +execFile[require('node:util').promisify.custom] = async (file, args) => { + if (file === '/usr/bin/open') { require('node:fs').writeFileSync(${JSON.stringify(handoff)}, JSON.stringify({file,args,home:process.env.HOME,userData:app.getPath('userData')})+'\\n',{mode:0o600}); return {stdout:'',stderr:''}; } + return require('node:util').promisify(nativeExecFile)(file,args); +};`; + await fs.writeFile(mainFile,original.replace(exact,wrapper));await asar.createPackage(unpacked,archive);asar.uncacheAll(); + const headerHash=createHash('sha256').update(asar.getRawHeader(archive).headerString).digest('hex'); + await run('/usr/libexec/PlistBuddy',['-c',`Set :ElectronAsarIntegrity:Resources/app.asar:hash ${headerHash}`,path.join(downloaded,'Contents/Info.plist')]); + await run('/usr/bin/codesign',['--force','--sign','-','--entitlements',path.resolve(__dirname,'../entitlements.mac.plist'),downloaded]); + await run('/usr/bin/codesign',['--verify','--deep','--strict',downloaded]); + const quarantine='0083;66000000;Rieke-E2E;00000000-0000-4000-8000-000000000001'; + // Quarantine is assigned only AFTER this source test clone has launched. + // The quarantined installed copy is never executed or stripped of quarantine. + const before=await bundleDigest(downloaded); + await check('downloaded clone displays explicit unsigned Install and Open before any backend starts',async()=>{ + application=await _electron.launch({executablePath:fixture.executable,args:[`--user-data-dir=${fixture.userData}`],env:{...process.env,HOME:fixture.home,TMPDIR:fixture.root,XDG_CONFIG_HOME:fixture.userData},chromiumSandbox:true,bypassCSP:false,timeout:45000}); + const actual=await application.evaluate(({app})=>({home:process.env.HOME,userData:app.getPath('userData'),appPath:app.getAppPath(),packaged:app.isPackaged})); + assert.equal(actual.home,fixture.home);assert.equal(actual.userData,path.join(fixture.userData,'installer'));assert.ok(actual.appPath.startsWith(downloaded+'/'));assert.equal(actual.packaged,true); + page=await application.firstWindow();await page.getByRole('heading',{name:'Install Rieke OS',exact:true}).waitFor(); + await page.getByText('Unsigned testing',{exact:true}).waitFor();assert.match(await page.locator('#detail').innerText(),/Open Anyway/); + await page.getByRole('button',{name:'Install and Open',exact:true}).waitFor(); + assert.equal(await fs.stat(target).then(()=>true,()=>false),false);assert.equal(await fs.stat(handoff).then(()=>true,()=>false),false); + assert.equal(await fs.stat(path.join(fixture.userData,'desktop-service.json')).then(()=>true,()=>false),false); + await page.screenshot({path:path.join(path.dirname(output),'bootstrap-install-and-open.png')}); + await run('/usr/bin/xattr',['-w','com.apple.quarantine',quarantine,downloaded]);return {bootstrap:true,no_automatic_install:true,no_backend:true,isolated_installer_profile:true}; + }); + await check('explicit Install and Open copies the complete verified bundle and preserves quarantine and installed profile',async()=>{ + const exited=new Promise(resolve=>application.process().once('exit',resolve));await page.getByRole('button',{name:'Install and Open',exact:true}).click(); + const code=await Promise.race([exited,new Promise((_r,reject)=>setTimeout(()=>reject(new Error('Installer failed to complete its native copy')),420000).unref())]);assert.equal(code,0); + const dispatch=JSON.parse(await fs.readFile(handoff,'utf8')); + assert.deepEqual(dispatch.args,['-n','-a',target,'--env',`HOME=${fixture.home}`,'--args',`--user-data-dir=${fixture.userData}`]);assert.equal(dispatch.file,'/usr/bin/open');assert.equal(dispatch.home,fixture.home); + assert.equal(await bundleDigest(target),before);assert.equal(await bundleDigest(downloaded),before); + assert.equal((await run('/usr/bin/xattr',['-p','com.apple.quarantine',target])).stdout.trim(),quarantine); + await verifyResources(path.join(target,'Contents/Resources/runtime'),manifest.resources);await run('/usr/bin/codesign',['--verify','--deep','--strict',target]); + return {real_complete_copy:true,copy_hash_identical:true,source_unchanged:true,quarantine_preserved:true,exact_isolated_launch_profile:true,os_dispatch_only_stubbed:true}; + }); + await check('installed copy cold starts into Your projects using the base isolated profile',async()=>{ + // A completely separate never-quarantined fixture qualifies profile startup. + fixture=await createFixture({reuse:false});receipt.unquarantined_profile_fixture_root=fixture.root; + const cleanTarget=fixture.bundle,cleanDownload=path.join(fixture.home,'Downloads','Rieke OS.app'),cleanHandoff=path.join(fixture.home,'launch-services-handoff.json'); + await fs.mkdir(path.dirname(cleanDownload),{recursive:true});await fs.rename(cleanTarget,cleanDownload); + const cleanArchive=path.join(cleanDownload,'Contents/Resources/app.asar'),cleanUnpacked=path.join(fixture.root,'profile-test-asar');asar.extractAll(cleanArchive,cleanUnpacked); + const cleanMain=path.join(cleanUnpacked,'main.cjs'),cleanOriginal=await fs.readFile(cleanMain,'utf8');assert.ok(cleanOriginal.includes(exact)); + await fs.writeFile(cleanMain,cleanOriginal.replace(exact,wrapper.replace(JSON.stringify(handoff),JSON.stringify(cleanHandoff))));await asar.createPackage(cleanUnpacked,cleanArchive);asar.uncacheAll(); + await run('/usr/libexec/PlistBuddy',['-c',`Set :ElectronAsarIntegrity:Resources/app.asar:hash ${createHash('sha256').update(asar.getRawHeader(cleanArchive).headerString).digest('hex')}`,path.join(cleanDownload,'Contents/Info.plist')]); + await run('/usr/bin/codesign',['--force','--sign','-','--entitlements',path.resolve(__dirname,'../entitlements.mac.plist'),cleanDownload]);await run('/usr/bin/codesign',['--verify','--deep','--strict',cleanDownload]); + application=await _electron.launch({executablePath:path.join(cleanDownload,'Contents/MacOS/Rieke OS'),args:[`--user-data-dir=${fixture.userData}`],env:{...process.env,HOME:fixture.home,TMPDIR:fixture.root,XDG_CONFIG_HOME:fixture.userData},chromiumSandbox:true,bypassCSP:false,timeout:45000}); + page=await application.firstWindow();await page.getByRole('heading',{name:'Install Rieke OS',exact:true}).waitFor(); + const exited=new Promise(resolve=>application.process().once('exit',resolve));await page.getByRole('button',{name:'Install and Open',exact:true}).click();assert.equal(await Promise.race([exited,new Promise((_r,reject)=>setTimeout(()=>reject(new Error('Clean installer did not finish')),420000).unref())]),0); + assert.deepEqual(JSON.parse(await fs.readFile(cleanHandoff,'utf8')).args,['-n','-a',cleanTarget,'--env',`HOME=${fixture.home}`,'--args',`--user-data-dir=${fixture.userData}`]); + assert.equal(await run('/usr/bin/xattr',['-p','com.apple.quarantine',cleanTarget]).then(()=>true,error=>{if(error.code===1)return false;throw error;}),false,'This startup fixture must never carry quarantine'); + fixture.bundle=cleanTarget;fixture.executable=path.join(cleanTarget,'Contents/MacOS/Rieke OS');({application,page}=await launch(fixture)); + await page.getByRole('heading',{name:'Your projects',exact:true}).waitFor({timeout:90000});assert.equal((await page.evaluate(()=>window.riekeDesktop.status())).channel,'unsigned-testing'); + await gracefulQuit(application,page);await verifyResources(path.join(cleanTarget,'Contents/Resources/runtime'),manifest.resources);return {manual_macos_approval_unqualified:true,separate_never_quarantined_fixture:true,real_installed_startup:true,base_profile_restored:true,native_orderly_exit:true,runtime_immutable:true}; + }); + assert.equal(receipt.failures.length,0);await write();console.log('Bootstrap receipt: '+output); +} +main().catch(async error=>{console.error(error.stack);receipt.failures.push({name:'bootstrap-suite',message:error.message});await write();process.exitCode=1;}); diff --git a/desktop/e2e/github-updates.e2e.cjs b/desktop/e2e/github-updates.e2e.cjs new file mode 100644 index 0000000..17e2102 --- /dev/null +++ b/desktop/e2e/github-updates.e2e.cjs @@ -0,0 +1,79 @@ +'use strict'; +// Only the official GitHub HTTPS transport is mapped to a loopback asset server +// inside an isolated test clone. Descriptor, ZIP, candidate/runtime validation, +// UI, draft/writer drain and ordinary Quit all run the packaged implementation. +const assert=require('node:assert/strict'),fs=require('node:fs/promises'),nativeFs=require('node:fs'),path=require('node:path'),http=require('node:http'); +const {createHash}=require('node:crypto'),asar=require('@electron/asar'); +const {createFixture,launch,gracefulQuit,ownedControl,run}=require('./helpers.cjs'); +const {verifyResources}=require('../updater-validation.cjs'); +const output=path.resolve(__dirname,'../../docs/dev/desktop-ui-e2e/github-update-receipt.json'); +const receipt={format:'rieke-packaged-github-update-ui-e2e',version:1,signed_qualification:false,checks:[],failures:[],method:'Version-only Current clone, official HTTPS GitHub URLs mapped only at transport boundary to real final descriptor and ZIP; no candidate validation or drain mocks'}; +let fixture,application,page,server;const counts={api:0,descriptor:0,archive:0}; +const delay=ms=>new Promise(resolve=>setTimeout(resolve,ms)); +async function write(){await fs.mkdir(path.dirname(output),{recursive:true});await fs.writeFile(output,JSON.stringify({...receipt,requests:counts},null,2)+'\n');} +async function check(name,fn){const start=Date.now();try{const evidence=await fn();receipt.checks.push({name,passed:true,elapsed_ms:Date.now()-start,evidence});console.log('PASS '+name);}catch(error){receipt.failures.push({name,message:error.message});await write();throw error;}await write();} +async function main(){ + fixture=await createFixture({reuse:false});receipt.fixture_root=fixture.root; + const published=path.resolve(__dirname,'../dist/mac-arm64/Rieke OS.app'),sourceManifestFile=path.join(published,'Contents/Resources/runtime/runtime-manifest.json'),sourceBytes=await fs.readFile(sourceManifestFile),sourceManifest=JSON.parse(sourceBytes); + receipt.source_manifest_sha256=createHash('sha256').update(sourceBytes).digest('hex');receipt.source_app_asar_sha256=createHash('sha256').update(await fs.readFile(path.join(published,'Contents/Resources/app.asar'))).digest('hex'); + const candidateVersion=sourceManifest.application_version;assert.equal(candidateVersion,'0.1.3','Test scenario requires the final 0.1.3 package'); + const zip=path.resolve(__dirname,`../dist/Rieke-OS-${candidateVersion}-arm64.zip`),descriptorPath=path.join(fixture.root,'desktop-release.json'); + await run(path.join(fixture.bundle,'Contents/Resources/runtime/python/bin/python3.11'),['-B',path.resolve(__dirname,'../../tools/desktop_test_release.py'),'--app',published,'--archive',zip,'--output',descriptorPath],{env:{...process.env,PYTHONDONTWRITEBYTECODE:'1'}}); + const descriptorBytes=await fs.readFile(descriptorPath),descriptor=JSON.parse(descriptorBytes);receipt.candidate_archive_sha256=descriptor.archive.sha256; + const tag=`desktop-test-v${candidateVersion}`,root=`https://github.com/maxwellsdm1867/Rieke-OS/releases/download/${tag}/`; + const releases=Buffer.from(JSON.stringify([{draft:false,prerelease:true,tag_name:tag,assets:[{name:'desktop-release.json',browser_download_url:root+'desktop-release.json',size:descriptorBytes.length},{name:descriptor.archive.filename,browser_download_url:root+descriptor.archive.filename,size:descriptor.archive.size}]}])); + server=http.createServer((request,response)=>{ + if(request.url==='/api'){counts.api++;response.writeHead(200,{'content-length':releases.length});response.end(releases);} + else if(request.url==='/descriptor'){counts.descriptor++;response.writeHead(200,{'content-length':descriptorBytes.length});response.end(descriptorBytes);} + else if(request.url==='/archive'){counts.archive++;response.writeHead(200,{'content-length':descriptor.archive.size});nativeFs.createReadStream(zip).pipe(response);} + else{response.writeHead(404);response.end();} + });await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve)); + const base=`http://127.0.0.1:${server.address().port}`,transport=path.join(fixture.root,'github-transport.cjs'); + await fs.writeFile(transport,`'use strict';const http=require('node:http');exports.transport=(url,{kind}={})=>{const target=url==='https://api.github.com/repos/maxwellsdm1867/Rieke-OS/releases?per_page=100&page=1'?'/api':url===${JSON.stringify(root+'desktop-release.json')}?'/descriptor':url===${JSON.stringify(root+descriptor.archive.filename)}?'/archive':null;if(!target)return Promise.reject(new Error('Unexpected official fixture URL'));return new Promise((resolve,reject)=>{http.get(${JSON.stringify(base)}+target,response=>resolve({statusCode:response.statusCode,headers:response.headers,body:response})).on('error',reject);});};\n`,{mode:0o600}); + const runtime=path.join(fixture.bundle,'Contents/Resources/runtime'),manifestFile=path.join(runtime,'runtime-manifest.json'),manifest=JSON.parse(await fs.readFile(manifestFile));manifest.application_version='0.1.2'; + const releaseNames=Object.keys(manifest.resources).filter(name=>name.endsWith('/rieke-release.json')); + assert.ok(releaseNames.includes('application/rieke-release.json')); + for(const name of releaseNames){const file=path.join(runtime,name),release=JSON.parse(await fs.readFile(file));release.version='0.1.2';const bytes=Buffer.from(JSON.stringify(release,null,2)+'\n');await fs.writeFile(file,bytes);manifest.resources[name]={sha256:createHash('sha256').update(bytes).digest('hex'),size:bytes.length};} + await fs.writeFile(manifestFile,JSON.stringify(manifest,null,2)+'\n'); + const archive=path.join(fixture.bundle,'Contents/Resources/app.asar'),unpacked=path.join(fixture.root,'update-ui-test-asar');asar.extractAll(archive,unpacked); + const mainFile=path.join(unpacked,'main.cjs'),original=await fs.readFile(mainFile,'utf8'),anchor='manifest: supervisor.manifest, distribution});';assert.ok(original.includes(anchor)); + await fs.writeFile(mainFile,original.replace(anchor,`manifest: supervisor.manifest, distribution, transport: require(${JSON.stringify(transport)}).transport});`)); + const packageFile=path.join(unpacked,'package.json'),pack=JSON.parse(await fs.readFile(packageFile));pack.version='0.1.2';await fs.writeFile(packageFile,JSON.stringify(pack,null,2)+'\n'); + await asar.createPackage(unpacked,archive);asar.uncacheAll();const plist=path.join(fixture.bundle,'Contents/Info.plist'); + await run('/usr/libexec/PlistBuddy',['-c','Set :CFBundleShortVersionString 0.1.2',plist]);await run('/usr/libexec/PlistBuddy',['-c','Set :CFBundleVersion 0.1.2',plist]); + await run('/usr/libexec/PlistBuddy',['-c',`Set :ElectronAsarIntegrity:Resources/app.asar:hash ${createHash('sha256').update(asar.getRawHeader(archive).headerString).digest('hex')}`,plist]); + await run('/usr/bin/codesign',['--force','--sign','-','--entitlements',path.resolve(__dirname,'../entitlements.mac.plist'),fixture.bundle]);await run('/usr/bin/codesign',['--verify','--deep','--strict',fixture.bundle]); + await verifyResources(runtime,manifest.resources);receipt.test_current_version='0.1.2'; + ({application,page}=await launch(fixture));page.on('pageerror',error=>receipt.failures.push({name:'renderer-pageerror',message:error.message})); + await page.getByRole('heading',{name:'Your projects',exact:true}).waitFor({timeout:90000}); + await check('background official release metadata creates a quiet version notice without downloading',async()=>{ + await page.waitForFunction(()=>[...document.querySelectorAll('.app-update-badge')].some(node=>node.textContent==='v0.1.3'),undefined,{timeout:30000}); + assert.ok(counts.api>0&&counts.descriptor>0);assert.equal(counts.archive,0);const status=await page.evaluate(()=>window.riekeDesktop.status());assert.equal(status.state,'Available');assert.equal(status.channel,'unsigned-testing');assert.equal(status.manual_updates,true);return {visible_available_version:'0.1.3',automatic_metadata:true,no_archive_download:true}; + }); + await check('explicit Check and Download prepare a fully validated real ZIP and show Restart to update',async()=>{ + await page.getByRole('button',{name:/^Release \/ Publish/}).first().click();const dialog=page.getByRole('dialog',{name:'Release / Publish',exact:true}); + assert.match(await dialog.innerText(),/Unsigned testing/);assert.doesNotMatch(await dialog.innerText(),/New versions download automatically|next launch applies/); + const before=counts.api;await dialog.getByRole('button',{name:'Check for updates',exact:true}).click();await page.waitForFunction(()=>window.riekeDesktop.status().then(s=>s.state==='Available'));assert.ok(counts.api>before);assert.equal(counts.archive,0); + await dialog.getByRole('button',{name:'Download update',exact:true}).click();await dialog.getByRole('button',{name:'Restart to update',exact:true}).waitFor({timeout:180000}); + const status=await page.evaluate(()=>window.riekeDesktop.status());assert.equal(status.state,'Ready');assert.equal(status.can_restart,true);assert.equal(counts.archive,1); + await page.screenshot({path:path.join(path.dirname(output),'github-testing-update-ready.png')});return {explicit_check:true,explicit_download:true,real_zip_validated:true,ready_version:status.available,no_install_before_restart:true}; + }); + if(process.env.RIEKE_E2E_H5)await check('Restart to update defers an actual importer while the current app remains usable',async()=>{ + await page.keyboard.press('Escape');await fs.mkdir(fixture.projects,{recursive:true});await page.getByRole('button',{name:/Start a brand new project/}).click();const form=page.locator('.onboarding-create-form');await form.getByRole('textbox').first().fill('Testing update writer fixture'); + await application.evaluate(({dialog},directory)=>{dialog.showOpenDialog=async()=>({canceled:false,filePaths:[directory]});},fixture.projects); + await form.getByRole('button',{name:'Browse: New project folder',exact:true}).click();const picker=page.getByRole('dialog',{name:'New project folder',exact:true});await picker.getByRole('checkbox',{name:'Create a new folder inside this location'}).check();await picker.getByRole('textbox',{name:'New folder name',exact:true}).fill('writer');await picker.getByRole('button',{name:'Use new folder',exact:true}).click();await page.getByRole('button',{name:'Create & open',exact:true}).click();await page.getByRole('button',{name:'Project overview',exact:true}).waitFor({timeout:90000}); + const author=page.getByRole('dialog',{name:'Tag author',exact:true});if(await author.waitFor({state:'visible',timeout:3000}).then(()=>true,()=>false)){await author.getByRole('textbox').fill('Update E2E');await author.getByRole('button',{name:'Create profile',exact:true}).click();} + const source=path.join(fixture.home,'writer.h5');await fs.copyFile(path.resolve(process.env.RIEKE_E2E_H5),source); + const job=await page.evaluate(async source=>{const response=await fetch('/api/imports',{method:'POST',headers:{'content-type':'application/json','X-Workspace-Request':'1'},body:JSON.stringify({source_path:source})});if(!response.ok)throw new Error(await response.text());return response.json();},source); + const before=await ownedControl(fixture,'health');await page.getByRole('button',{name:/^Release \/ Publish/}).first().click();const dialog=page.getByRole('dialog',{name:'Release / Publish',exact:true});await dialog.getByRole('button',{name:'Restart to update',exact:true}).click();await dialog.getByRole('alert').waitFor({timeout:30000}); + assert.match(await dialog.getByRole('alert').innerText(),/import|work|busy|writer/i);assert.equal(page.isClosed(),false);assert.equal((await ownedControl(fixture,'health')).pid,before.pid);assert.equal((await page.evaluate(()=>window.riekeDesktop.status())).state,'Ready'); + let done;for(let n=0;n<240;n++){done=await page.evaluate(async id=>(await fetch('/api/jobs').then(r=>r.json())).jobs.find(j=>j.job_uuid===id),job.job_uuid);if(['complete','completed','failed','cancelled'].includes(done?.status))break;await delay(500);}assert.ok(['complete','completed'].includes(done?.status));await page.keyboard.press('Escape');return {busy_restart_deferred:true,root_preserved:true,current_app_usable:true,real_import_completed:true}; + }); + await check('ordinary Quit with a prepared testing update leaves the current complete app installed',async()=>{ + await page.keyboard.press('Escape');assert.equal((await page.evaluate(()=>window.riekeDesktop.status())).state,'Ready');await gracefulQuit(application,page);application=null; + const after=JSON.parse(await fs.readFile(manifestFile));assert.equal(after.application_version,'0.1.2');await verifyResources(runtime,manifest.resources); + assert.equal(await fs.stat(path.join(path.dirname(fixture.bundle),'.Rieke OS.previous.app')).then(()=>true,()=>false),false);const cache=path.join(fixture.userData,'updates','unsigned-testing');const entries=await fs.readdir(cache).catch(()=>[]);assert.ok(!entries.some(name=>/^install-.*\.json$/.test(name)));return {ordinary_quit_did_not_install:true,current_version:'0.1.2',runtime_immutable:true,native_orderly_exit:true}; + }); + assert.equal(receipt.failures.length,0);await write();await new Promise(resolve=>server.close(resolve));server=null;console.log('GitHub update UI receipt: '+output); +} +main().catch(async error=>{console.error(error.stack);receipt.failures.push({name:'github-update-suite',message:error.message});await write();server?.close();process.exitCode=1;}); diff --git a/desktop/e2e/helpers.cjs b/desktop/e2e/helpers.cjs new file mode 100644 index 0000000..27577e3 --- /dev/null +++ b/desktop/e2e/helpers.cjs @@ -0,0 +1,54 @@ +'use strict'; +const fs = require('node:fs/promises'); +const path = require('node:path'); +const os = require('node:os'); +const {execFile} = require('node:child_process'); +const {promisify} = require('node:util'); +const {_electron} = require('playwright'); +const run = promisify(execFile); +async function createFixture({reuse = true} = {}) { + if (reuse && process.env.RIEKE_E2E_FIXTURE_ROOT) { + const root = await fs.realpath(process.env.RIEKE_E2E_FIXTURE_ROOT); + if (!root.startsWith(await fs.realpath(os.tmpdir()) + path.sep) || !path.basename(root).startsWith('rieke-packaged-ui-e2e-')) throw new Error('Reusable fixture must be an owned isolated test directory'); + const home = path.join(root, 'home'), bundle = path.join(home, 'Applications', 'Rieke OS.app'); + if ((await fs.stat(root)).uid !== process.getuid()) throw new Error('Test directory owner mismatch'); + return {root, home, bundle, userData: path.join(home, 'state'), executable: path.join(bundle, 'Contents/MacOS/Rieke OS'), projects: path.join(home, 'projects')}; + } + const root = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-packaged-ui-e2e-'))); + const home = path.join(root, 'home'); + const bundle = path.join(home, 'Applications', 'Rieke OS.app'); + const userData = path.join(home, 'state'); + await fs.mkdir(path.dirname(bundle), {recursive: true}); await fs.mkdir(userData, {recursive: true}); + await run('/usr/bin/ditto', [path.resolve(__dirname, '../dist/mac-arm64/Rieke OS.app'), bundle]); + return {root, home, bundle, userData, executable: path.join(bundle, 'Contents/MacOS/Rieke OS'), projects: path.join(home, 'projects')}; +} +async function launch(fixture) { + const application = await _electron.launch({executablePath: fixture.executable, args: [`--user-data-dir=${fixture.userData}`], + env: {...process.env, HOME: fixture.home, TMPDIR: fixture.root, XDG_CONFIG_HOME: fixture.userData}, + chromiumSandbox: true, bypassCSP: false, timeout: 45000}); + fixture.activeApplication = application; + const actual = await application.evaluate(({app}) => ({home: process.env.HOME, userData: app.getPath('userData'), + appPath: app.getAppPath(), packaged: app.isPackaged, pid: process.pid, electronVersion: process.versions.electron})); + if (actual.home !== fixture.home || actual.userData !== fixture.userData || !actual.appPath.startsWith(fixture.bundle + '/')) + throw new Error('Application state is not isolated; no UI interactions are permitted'); + const page = await application.firstWindow({timeout: 45000}); + return {application, page, actual}; +} +async function gracefulQuit(application, page) { + const exited = new Promise(resolve => application.process().once('exit', resolve)); + await page.evaluate(() => { void window.riekeDesktop.quit(); }); + const code = await Promise.race([exited, new Promise((_resolve, reject) => setTimeout(() => reject(new Error('App did not acknowledge orderly exit')), 45000).unref())]); + if (code !== 0) throw new Error('App exited without a successful orderly shutdown'); +} +async function ownedControl(fixture, endpoint, body) { + const record = JSON.parse(await fs.readFile(path.join(fixture.userData, 'desktop-service.json'), 'utf8')); + if (!record.executable.startsWith(fixture.bundle + '/')) throw new Error('Service does not belong to this test bundle'); + const command = await run('/bin/ps', ['eww', '-p', String(record.pid), '-o', 'command=']); + const capability = command.stdout.match(/(?:^|\s)RIEKE_DESKTOP_CAPABILITY=([a-f0-9]{64})(?:\s|$)/)?.[1]; + if (!capability) throw new Error('No capability for the owned test service'); + const response = await fetch(`http://127.0.0.1:${record.port}/api/desktop/${endpoint}`, {method: body === undefined ? 'GET' : 'POST', + headers: {'X-Rieke-Desktop-Capability': capability, 'X-Workspace-Request': '1', 'Content-Type': 'application/json'}, + ...(body === undefined ? {} : {body: JSON.stringify(body)}), signal: AbortSignal.timeout(35000)}); + const value = await response.json(); if (!response.ok) throw new Error(value.error || 'Owned test control failed'); return value; +} +module.exports = {createFixture, launch, gracefulQuit, ownedControl, run}; diff --git a/desktop/e2e/packaged.e2e.cjs b/desktop/e2e/packaged.e2e.cjs new file mode 100644 index 0000000..f7ebef1 --- /dev/null +++ b/desktop/e2e/packaged.e2e.cjs @@ -0,0 +1,410 @@ +'use strict'; +const assert = require('node:assert/strict'); +const fs = require('node:fs/promises'); +const path = require('node:path'); +const http = require('node:http'); +const {spawn} = require('node:child_process'); +const {createHash, randomUUID} = require('node:crypto'); +const {chromium} = require('playwright'); +const {createFixture, launch, gracefulQuit, ownedControl, run} = require('./helpers.cjs'); +const {verifyResources} = require('../updater-validation.cjs'); +const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); +const output = path.resolve(__dirname, '../../docs/dev/desktop-ui-e2e'); +let fixture, application, page, recoveredBrowser, deliberateCrash = false; +const receipt = {format: 'rieke-packaged-ui-e2e', version: 1, signed_qualification: false, checks: [], failures: [], + method: 'Playwright Electron 1.63.0; exact packaged app clone; isolated HOME and standard --user-data-dir; sandbox enabled and CSP intact; native chooser return values stubbed only'}; +receipt.run_id = randomUUID().slice(0, 8); +const projectName = 'Electron lifecycle fixture ' + receipt.run_id; +process.on('uncaughtException', error => { + // Pinned Playwright throws this client assertion when Electron recovers the + // same target after forcefullyCrashRenderer. The app is inspected through + // its actual owned WebContents API during that fault, instead of its stale + // Playwright Page session. Other unexpected exceptions still fail the run. + if (deliberateCrash && error.message === 'Target crashed') {receipt.playwright_crash_session_warnings = (receipt.playwright_crash_session_warnings || 0) + 1; return;} + throw error; +}); +async function chooseTestProfile() { + const dialog = page.getByRole('dialog', {name: 'Tag author', exact: true}); + const visible = await dialog.waitFor({state: 'visible', timeout: 3000}).then(() => true).catch(() => false); + if (visible) { + const existing = dialog.getByRole('button', {name: 'Electron E2E', exact: true}); + if (await existing.count()) await existing.first().click(); + else {await dialog.getByRole('textbox').fill('Electron E2E'); await dialog.getByRole('button', {name: 'Create profile', exact: true}).click();} + await dialog.waitFor({state: 'hidden'}); + } +} +async function chooseNewProjectFolder(form, name) { + const selected = form.locator('#new-project-directory'); + assert.equal(await selected.getAttribute('readonly'), ''); + await application.evaluate(({dialog}, directory) => {dialog.showOpenDialog = async () => ({canceled:false,filePaths:[directory]});}, fixture.projects); + await form.getByRole('button', {name:'Browse: New project folder',exact:true}).click(); + const picker = page.getByRole('dialog', {name:'New project folder',exact:true}); + await picker.getByRole('checkbox', {name:'Create a new folder inside this location'}).check(); + await picker.getByRole('textbox', {name:'New folder name',exact:true}).fill(name); + await picker.getByRole('button', {name:'Use new folder',exact:true}).click(); + await picker.waitFor({state:'hidden'}); + assert.equal(await selected.inputValue(), path.join(fixture.projects,name)); +} +async function verifyHeaderIcon(selector, headerSelector, screenName) { + const measurements = []; + try { + for (const width of [1440, 960]) { + await application.evaluate(({BrowserWindow}, width) => BrowserWindow.getAllWindows()[0].setContentSize(width, 900), width); + await page.waitForFunction(({selector, width}) => { + const icon = document.querySelector(selector); + return window.innerWidth === width && icon?.complete && icon.naturalWidth > 0; + }, {selector, width}, {timeout: 15000}); + const geometry = await page.evaluate(({selector, headerSelector}) => { + const icon = document.querySelector(selector), header = document.querySelector(headerSelector); + const bounds = node => {const r = node.getBoundingClientRect(); return {left:r.left, right:r.right, top:r.top, bottom:r.bottom, width:r.width, height:r.height};}; + const others = [...header.children].filter(node => node !== icon && !node.classList.contains('spacer') && node.getClientRects().length && getComputedStyle(node).visibility !== 'hidden') + .map(node => ({tag: node.tagName, className: node.className, rect: bounds(node)})).filter(node => node.rect.width > 0 && node.rect.height > 0); + return {viewport: window.innerWidth, source: new URL(icon.currentSrc).pathname, naturalWidth:icon.naturalWidth, naturalHeight:icon.naturalHeight, + icon:bounds(icon), header:bounds(header), others}; + }, {selector, headerSelector}); + await page.screenshot({path: path.join(output, `${screenName}-${width}.png`)}); + assert.equal(geometry.source, '/rieke-os-icon.png'); assert.ok(geometry.naturalWidth > 0); + const expectedSize = selector === '.onboarding-app-icon' ? 48 : 32; + assert.equal(geometry.icon.width, expectedSize); assert.equal(geometry.icon.height, expectedSize); + assert.ok(geometry.icon.left >= geometry.header.left && geometry.icon.right <= geometry.header.right + 1 && geometry.icon.right <= width + 1, + 'App icon must remain inside its header and viewport: ' + JSON.stringify(geometry)); + assert.ok(geometry.icon.left > (geometry.header.left + geometry.header.right) / 2, 'App icon must be on the right'); + for (const sibling of geometry.others) { + const r = sibling.rect, icon = geometry.icon; + assert.ok(!(r.left < icon.right - 1 && r.right > icon.left + 1 && r.top < icon.bottom - 1 && r.bottom > icon.top + 1), + 'App icon overlaps an adjacent header control: ' + JSON.stringify({width, sibling, icon})); + } + measurements.push({viewport: width, naturalWidth: geometry.naturalWidth, icon: geometry.icon, header: geometry.header}); + } + } finally {await application.evaluate(({BrowserWindow}) => BrowserWindow.getAllWindows()[0].setContentSize(1440, 900));} + return {actual_packaged_icon_loaded: true, header_right: true, no_icon_overlap: true, native_window_widths: measurements}; +} +async function writeReceipt() { await fs.mkdir(output, {recursive: true}); await fs.writeFile(path.join(output, 'receipt.json'), JSON.stringify(receipt, null, 2) + '\n'); } +async function check(name, fn) { + const start = Date.now(); + try { const evidence = await fn(); receipt.checks.push({name, passed: true, elapsed_ms: Date.now() - start, ...(evidence ? {evidence} : {})}); console.log('PASS ' + name); } + catch (error) { receipt.failures.push({name, message: error.message}); console.error('FAIL ' + name + ': ' + error.message); await writeReceipt(); throw error; } + await writeReceipt(); +} +async function start(heading = 'Your projects') { + const launched = await launch(fixture); ({application, page} = launched); + page.on('pageerror', error => receipt.failures.push({name: 'renderer-pageerror', message: error.message})); + await page.getByRole('heading', {name: heading, exact: true}).waitFor({timeout: 90000}); + return launched.actual; +} +async function main() { + fixture = await createFixture(); console.log('Isolated fixture: ' + fixture.root); + const runtime = path.join(fixture.bundle, 'Contents/Resources/runtime'); + const bytes = await fs.readFile(path.join(runtime, 'runtime-manifest.json')); const manifest = JSON.parse(bytes); + receipt.manifest_sha256 = createHash('sha256').update(bytes).digest('hex'); receipt.application_version = manifest.application_version; + receipt.app_asar_sha256 = createHash('sha256').update(await fs.readFile(path.join(fixture.bundle, 'Contents/Resources/app.asar'))).digest('hex'); + receipt.app_icon_sha256 = createHash('sha256').update(await fs.readFile(path.join(runtime, 'frontend/rieke-os-icon.png'))).digest('hex'); + assert.equal(receipt.app_icon_sha256, '614f7bcd44ced5ff8cf76f648e7a4e23ec45bee3236ea5ad17f59e3a1e173483', 'Packaged renderer must use the existing app icon'); + await check('cold packaged launcher and state isolation', async () => {const actual = await start(); assert.equal(actual.packaged, true); assert.equal(actual.electronVersion, '44.5.0'); return {isolated_user_state: true, packaged: true, electron_version: actual.electronVersion};}); + await check('launcher actual app icon loads at upper right at normal and narrow native widths', + () => verifyHeaderIcon('.onboarding-app-icon', '.project-onboarding>header', 'launcher-icon')); + await check('renderer isolation, sandbox and CSP', async () => { + const settings = await application.evaluate(({BrowserWindow}) => { + const prefs = BrowserWindow.getAllWindows()[0].webContents.getLastWebPreferences(); + return {contextIsolation: prefs.contextIsolation, sandbox: prefs.sandbox, nodeIntegration: prefs.nodeIntegration, webSecurity: prefs.webSecurity}; + }); + assert.deepEqual(settings, {contextIsolation: true, sandbox: true, nodeIntegration: false, webSecurity: true}); + assert.deepEqual(await page.evaluate(() => ({require: typeof require, process: typeof process, rawIpc: typeof window.riekeDesktop.ipcRenderer})), {require: 'undefined', process: 'undefined', rawIpc: 'undefined'}); + const inlineRan = await page.evaluate(() => { const script = document.createElement('script'); script.textContent = 'window.__inline_e2e=true'; document.body.append(script); return window.__inline_e2e === true; }); + assert.equal(inlineRan, false); return settings; + }); + await check('testing updates preserve explicit download, restart and bootstrap boundaries', async () => { + const status = await page.evaluate(() => window.riekeDesktop.status()); + if(status.channel==='unsigned-testing') { + assert.equal(status.manual_updates,true); + assert.ok(!['Downloading','Validating','Ready','Draining','Installing'].includes(status.state), 'Background checks must never download or install'); + const result=await page.evaluate(()=>window.riekeDesktop.restartToUpdate());assert.equal(result.ready,false); + } else assert.equal(status.state, 'Deferred'); + const message = await page.evaluate(async () => { try { await window.riekeDesktop.installAndOpen(); return ''; } catch (error) { return error.message; } }); + assert.match(message, /before backend startup/); + }); + await check('malformed draft IPC and external release URLs reject', async () => { + const results = await page.evaluate(async () => { + const actions = [() => window.riekeDesktop.saveDraft({projectId: '../../escape', value: {}}), + () => window.riekeDesktop.saveDraft({projectId: 'launcher', value: {}, path: '/outside'}), + () => window.riekeDesktop.loadDraft('../../escape'), () => window.riekeDesktop.openReleaseNotes('https://evil.example/'), + () => window.riekeDesktop.acknowledgeDrafts('foreign-request', {ok: true})]; + return Promise.all(actions.map(async action => {try {await action(); return false;} catch {return true;}})); + }); assert.deepEqual(results, [true, true, true, true, true]); + }); + await check('renderer cannot drain, stop or source-update services', async () => { + const statuses = await page.evaluate(async () => Promise.all(['/api/desktop/drain', '/api/desktop/stop', '/api/desktop/authorize-project'].map(async url => + (await fetch(url, {method: 'POST', headers: {'Content-Type': 'application/json', 'X-Workspace-Request': '1'}, body: '{}'})).status))); + assert.deepEqual(statuses, [403, 403, 403]); + const sourceStatuses = await page.evaluate(async () => Promise.all(['/api/app/updates', '/api/app/updates/check', '/api/app/updates/stage', '/api/app/updates/download'] + .map(async url => (await fetch(url)).status))); + assert.deepEqual(sourceStatuses, [409, 409, 409, 409]); + }); + await check('scientific project creation cannot write into packaged resources or redirected parents', async () => { + const direct = path.join(fixture.bundle, 'Contents/Resources/forbidden-project'); + const alias = path.join(fixture.root, 'resource-parent-alias-' + receipt.run_id); + await fs.symlink(path.join(fixture.bundle, 'Contents/Resources'), alias); + for (const directory of [direct, path.join(alias, 'forbidden-project'), + path.join(fixture.bundle, 'forbidden-project'), path.join(fixture.bundle, 'Contents/MacOS/forbidden-project')]) { + const result = await page.evaluate(async project_directory => { + const response = await fetch('/api/projects', {method: 'POST', headers: {'Content-Type': 'application/json', 'X-Workspace-Request': '1'}, body: JSON.stringify({name: 'Must not be created', project_directory})}); + return {status: response.status, value: await response.json()}; + }, directory); + assert.equal(result.status, 400); assert.ok(result.value.error); + await assert.rejects(fs.stat(directory), {code: 'ENOENT'}); + } + }); + await check('foreign navigation, popups and cross-origin requests blocked', async () => { + let visits = 0; const server = http.createServer((_request, response) => {visits++; response.end('foreign');}); + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); const target = `http://127.0.0.1:${server.address().port}/`; + const previous = page.url(); + try { + await page.evaluate(url => {window.open(url); window.location.assign(url);}, target); await delay(600); + assert.equal(page.url(), previous); assert.equal(application.windows().length, 1); assert.equal(visits, 0); + const blocked = await page.evaluate(async url => {try {await fetch(url); return false;} catch {return true;}}, target); assert.equal(blocked, true); + await page.evaluate(url => {const frame = document.createElement('iframe'); frame.src = url; document.body.append(frame);}, target); await delay(100); assert.equal(visits, 0); + await page.evaluate(() => document.querySelectorAll('iframe').forEach(frame => frame.remove())); + // Chromium reports the deliberately denied navigation to CDP before + // Electron cancels it. Reset this test-created pending-navigation state. + await application.evaluate(({BrowserWindow}) => BrowserWindow.getAllWindows()[0].webContents.reload()); + await page.getByRole('heading', {name: 'Your projects', exact: true}).waitFor({timeout: 15000}); + } finally { await new Promise(resolve => server.close(resolve)); } + }); + await check('foreign renderer IPC cannot access desktop controls', async () => { + const preload = path.join(fixture.root, 'foreign-preload.cjs'); + await fs.writeFile(preload, "const {contextBridge,ipcRenderer}=require('electron');contextBridge.exposeInMainWorld('foreignProbe',{request:()=>ipcRenderer.invoke('desktop:status').then(()=>({accepted:true}),e=>({accepted:false,message:e.message}))});"); + const result = await application.evaluate(async ({BrowserWindow}, preload) => { + const foreign = new BrowserWindow({show: false, webPreferences: {sandbox: true, contextIsolation: true, nodeIntegration: false, preload}}); + try {await foreign.loadURL('data:text/html,

Foreign test renderer

'); return await foreign.webContents.executeJavaScript('window.foreignProbe.request()');} + finally {foreign.destroy();} + }, preload); + assert.equal(result.accepted, false); assert.match(result.message, /Unauthorized desktop frame/); + }); + await check('native project-folder chooser uses typed result', async () => { + await fs.mkdir(fixture.projects, {recursive: true}); + await application.evaluate(({dialog}, directory) => {dialog.showOpenDialog = async () => ({canceled: false, filePaths: [directory]});}, fixture.projects); + assert.equal(await page.evaluate(() => window.riekeDesktop.chooseProjectFolder()), fixture.projects); + await application.evaluate(({dialog}) => {dialog.showOpenDialog = async () => ({canceled: true, filePaths: []});}); + assert.equal(await page.evaluate(() => window.riekeDesktop.chooseProjectFolder()), null); + }); + await check('duplicate launch preserves one owner and existing backend', async () => { + const before = await ownedControl(fixture, 'health'); + const child = spawn(fixture.executable, [`--user-data-dir=${fixture.userData}`], {env: {...process.env, HOME: fixture.home, TMPDIR: fixture.root}, stdio: 'ignore'}); + const code = await Promise.race([new Promise(resolve => child.once('exit', resolve)), delay(10000).then(() => {throw new Error('Duplicate app did not exit');})]); + assert.equal(code, 0); assert.equal((await ownedControl(fixture, 'health')).pid, before.pid); assert.equal(application.windows().length, 1); + }); + await check('corrupted saved view is visible, blocks overwrite and supports preserved quit or explicit reset', async () => { + await gracefulQuit(application, page); application = null; page = null; + const filename = path.join(fixture.userData, 'drafts', 'launcher.json'); + const valid = JSON.parse(await fs.readFile(filename, 'utf8')); + const corrupted = '{intentional unreadable saved-view fixture'; await fs.writeFile(filename, corrupted); + await start('Saved view needs recovery'); + assert.ok((await page.getByRole('alert').innerText()).includes('saved view')); + await delay(3300); assert.equal(await fs.readFile(filename, 'utf8'), corrupted); + assert.equal(await page.evaluate(async value => {try {await window.riekeDesktop.saveDraft({projectId: 'launcher', value}); return false;} catch {return true;}}, valid), true); + assert.equal((await page.evaluate(() => window.riekeDesktop.quit())).ready, false); + await page.screenshot({path: path.join(output, 'corrupted-view-recovery.png')}); + const exited = new Promise(resolve => application.process().once('exit', resolve)); + await page.getByRole('button', {name: 'Keep saved view and quit', exact: true}).click(); + assert.equal(await exited, 0); application = null; page = null; + assert.equal(await fs.readFile(filename, 'utf8'), corrupted); + await start('Saved view needs recovery'); + await page.getByRole('button', {name: 'Start with a new view', exact: true}).click(); + await page.getByRole('heading', {name: 'Your projects', exact: true}).waitFor(); + const backups = (await fs.readdir(path.dirname(filename))).filter(name => name.startsWith('launcher.corrupt-')); + assert.ok((await Promise.all(backups.map(name => fs.readFile(path.join(path.dirname(filename), name), 'utf8')))).includes(corrupted)); + assert.equal(await page.evaluate(async () => {try {await window.riekeDesktop.resetDraft('launcher'); return false;} catch {return true;}}), true); + return {visible_recovery: true, corrupt_bytes_preserved: true, ordinary_quit_deferred: true, preserved_quit_acknowledged: true, explicit_reset_preserved_backup: true}; + }); + await check('create and open project through actual React interface', async () => { + await page.getByRole('button', {name: /Start a brand new project/}).click(); + const form = page.locator('.onboarding-create-form'); + await form.getByRole('textbox').nth(0).fill(projectName); + const folderBeforeCancel=await form.locator('#new-project-directory').inputValue(); + await application.evaluate(({dialog})=>{dialog.showOpenDialog=async()=>({canceled:true,filePaths:[]});}); + await form.getByRole('button',{name:'Browse: New project folder',exact:true}).click(); + await form.getByRole('button',{name:'Browse: New project folder',exact:true}).waitFor({state:'visible'}); + await page.waitForFunction(()=>!document.querySelector('.folder-path-control button')?.disabled); + assert.equal(await form.locator('#new-project-directory').inputValue(),folderBeforeCancel); + assert.equal(await page.getByRole('dialog',{name:'New project folder',exact:true}).count(),0); + assert.equal(await fs.stat(path.join(fixture.projects,receipt.run_id)).then(()=>true,()=>false),false); + assert.equal(await form.getByRole('button',{name:'Create & open',exact:true}).isDisabled(),true); + await chooseNewProjectFolder(form, receipt.run_id); + await page.getByRole('button', {name: 'Create & open', exact: true}).click(); + await page.getByRole('button', {name: 'Project overview', exact: true}).waitFor({timeout: 90000}); + assert.match(await page.title(), /Electron lifecycle fixture/); + const project = await page.evaluate(() => fetch('/api/projects').then(response => response.json())); + receipt.test_project_uuid = project.current_project_uuid; assert.ok(project.current_project_uuid); + await chooseTestProfile(); + await page.screenshot({path: path.join(output, 'project.png')}); + }); + await check('workspace actual app icon loads at upper right without overlap at normal and narrow native widths', + () => verifyHeaderIcon('.header-app-icon', '.app-header', 'workspace-icon')); + await check('rapid warm project navigation persists the current view before document replacement', async () => { + const secondName = projectName + ' second'; + await page.locator('.sidebar').getByRole('button', {name: /Start a brand new project/}).click(); + const form = page.locator('.onboarding-create-form'); await form.getByRole('textbox').nth(0).fill(secondName); + await chooseNewProjectFolder(form, receipt.run_id + '-second'); + await page.getByRole('button', {name: 'Create & open', exact: true}).click(); + await page.waitForFunction(expected => document.title.startsWith(expected), secondName, {timeout: 90000}); await chooseTestProfile(); + receipt.second_project_uuid = (await page.evaluate(() => fetch('/api/projects').then(response => response.json()))).current_project_uuid; + assert.ok(receipt.second_project_uuid); + await page.getByRole('navigation', {name: 'Research projects'}).getByRole('button', {name: projectName, exact: true}).click(); + await page.waitForFunction(expected => document.title.startsWith(expected) && !document.title.includes(' second'), projectName, {timeout: 30000}); + const navigationStart = Date.now(); + await page.getByRole('button', {name: 'Activity & logs', exact: true}).click(); + await page.getByRole('navigation', {name: 'Research projects'}).getByRole('button', {name: secondName, exact: true}).click(); + await page.waitForFunction(expected => document.title.startsWith(expected), secondName, {timeout: 30000}); + const saved = JSON.parse(await fs.readFile(path.join(fixture.userData, 'drafts', receipt.test_project_uuid + '.json'))); + assert.equal(saved.value.route.page, 'activity'); + await page.getByRole('navigation', {name: 'Research projects'}).getByRole('button', {name: projectName, exact: true}).click(); + await page.waitForFunction(expected => document.title.startsWith(expected) && !document.title.includes(' second'), projectName, {timeout: 30000}); + await page.waitForFunction(() => [...document.querySelectorAll('.nav-item.active')].some(item => item.textContent.includes('Activity & logs'))); + return {warm_document_handoff: true, route_persisted: 'activity', elapsed_ms: Date.now() - navigationStart}; + }); + await check('missing saved view opens normally without corrupt-draft recovery', async () => { + const missing = path.join(fixture.userData, 'drafts', receipt.second_project_uuid + '.json'); + await fs.unlink(missing); + const secondName = projectName + ' second'; + await page.getByRole('navigation', {name: 'Research projects'}).getByRole('button', {name: secondName, exact: true}).click(); + await page.waitForFunction(expected => document.title.startsWith(expected), secondName, {timeout: 30000}); + await page.waitForFunction(() => [...document.querySelectorAll('.nav-item.active')].some(item => item.textContent.includes('Project overview'))); + assert.equal(await page.getByRole('heading', {name: 'Saved view needs recovery', exact: true}).count(), 0); + await page.getByRole('navigation', {name: 'Research projects'}).getByRole('button', {name: projectName, exact: true}).click(); + await page.waitForFunction(expected => document.title.startsWith(expected) && !document.title.includes(' second'), projectName, {timeout: 30000}); + return {missing_draft_treated_as_new_view: true}; + }); + if (process.env.RIEKE_E2E_H5) await check('actual active import defers close without stopping any writer', async () => { + const copied = path.join(fixture.root, 'scientific-fixture.h5'); await fs.copyFile(process.env.RIEKE_E2E_H5, copied); + const job = await page.evaluate(async source_path => { + const response = await fetch('/api/imports', {method: 'POST', headers: {'Content-Type': 'application/json', 'X-Workspace-Request': '1'}, body: JSON.stringify({source_path})}); + const value = await response.json(); if (response.status !== 202) throw new Error(value.error || 'Import was not accepted'); return value; + }, copied); + const before = await ownedControl(fixture, 'health'); + let status; + for (let index = 0; index < 80; index++) { + status = await page.evaluate(async uuid => (await fetch('/api/jobs').then(response => response.json())).jobs.find(job => job.job_uuid === uuid), job.job_uuid); + if (status && !['queued', 'waiting'].includes(status.status)) break; + await delay(250); + } + assert.ok(status && !['complete', 'completed', 'failed', 'cancelled'].includes(status.status)); + const result = await page.evaluate(() => window.riekeDesktop.quit()); assert.equal(result.ready, false); + assert.equal((await ownedControl(fixture, 'health')).pid, before.pid); assert.equal(page.isClosed(), false); + await application.evaluate(({BrowserWindow}) => BrowserWindow.getAllWindows()[0].close()); + await delay(500); + assert.equal(page.isClosed(), false); assert.equal((await ownedControl(fixture, 'health')).pid, before.pid); + for (let index = 0; index < 240; index++) { + status = await page.evaluate(async uuid => (await fetch('/api/jobs').then(response => response.json())).jobs.find(job => job.job_uuid === uuid), job.job_uuid); + if (['complete', 'completed', 'failed', 'cancelled'].includes(status?.status)) break; + await delay(500); + } + assert.ok(['complete', 'completed'].includes(status?.status), 'Import must finish successfully before test shutdown'); + // Completion is observed by the UI on its own polling cycle. Close its + // automatic review explicitly after it appears, rather than sending Escape + // before the dialog has been mounted. + const review=page.getByRole('dialog',{name:'Review imported data',exact:true}); + if(await review.waitFor({state:'visible',timeout:10000}).then(()=>true,()=>false)) { + await review.getByRole('button',{name:'Close import review',exact:true}).click(); + await review.waitFor({state:'hidden'}); + } + await page.keyboard.press('Escape'); + return {real_import: true, bridge_quit_deferred: true, native_window_close_deferred: true, root_pid_preserved: true, completed: true}; + }); + if(process.env.RIEKE_E2E_H5) await check('real protocol inspection uses combined epoch and cell pages with registered metadata and a plotted response',async()=>{ + await page.keyboard.press('Escape'); + const overview=await page.evaluate(()=>fetch('/api/overview').then(response=>response.json())); + const protocol=overview.protocols?.[0];assert.ok(protocol?.protocol_uuid,'Imported protocols must be available'); + let combined=null,inspectedProtocolUuid=null;const pending=[]; + const observe=response=>{ + const url=new URL(response.url()); + if(/^\/api\/protocols\/[^/]+\/epochs$/.test(url.pathname)&&url.searchParams.get('include_cells')==='true'&&response.status()===200) + pending.push(response.json().then(value=>{combined=value;inspectedProtocolUuid=url.pathname.split('/')[3];})); + }; + page.on('response',observe); + try{ + await page.getByRole('button',{name:'Project overview',exact:true}).click(); + await page.locator('.ov-protocol-row:visible').first().click({timeout:90000}); + await page.getByRole('button',{name:'Open inspection',exact:true}).click(); + const tree=page.locator('.inspection-cell-tree');await tree.waitFor({state:'visible',timeout:90000}); + await tree.locator('.cell-tree-date>summary').first().click(); + await tree.locator('.cell-tree-cell>summary').first().click(); + await tree.getByRole('button',{name:/^Inspect .* epoch 1$/}).first().click(); + await page.getByRole('region',{name:'Recorded response viewer',exact:true}).waitFor({timeout:90000}); + await page.waitForFunction(()=>{const canvas=document.querySelector('.tv-base');return canvas?.width>0&&!document.querySelector('.tv-loading')&&!document.querySelector('.tv-error');},undefined,{timeout:90000}); + const details=page.getByRole('button',{name:'Details',exact:true}); + if(await details.getAttribute('aria-pressed')!=='true')await details.click(); + await page.getByRole('heading',{name:'Epoch details',exact:true}).waitFor(); + await page.getByRole('button',{name:'All fields',exact:true}).click(); + assert.ok(await page.locator('.metadata-panel-section').count()>0); + const fields=await page.evaluate(()=>fetch('/api/metadata/fields').then(response=>response.json())); + assert.ok(Array.isArray(fields.fields)&&fields.fields.length>0,'Registered metadata fields must match the bundled frontend'); + await Promise.all(pending);assert.ok(combined?.epochs?.length>0&&combined?.cells?.length>0,'Actual UI must receive combined epochs and cells'); + assert.ok(combined.query_revision);assert.ok(Number.isSafeInteger(combined.expected_binding_version)); + assert.ok(!await page.getByText('Predicate field catalog unavailable.',{exact:false}).count()); + return {real_epoch_inspection:true,trace_canvas_loaded:true,combined_epoch_count:combined.epochs.length,combined_cell_count:combined.cells.length, + metadata_field_count:fields.fields.length,metadata_panel_visible:true,protocol_uuid:inspectedProtocolUuid}; + }finally{page.off('response',observe);} + }); + await check('durable real renderer draft survives orderly close and cold restart', async () => { + await page.getByRole('button', {name: 'Project files', exact: true}).click(); + await gracefulQuit(application, page); application = null; page = null; + const saved = JSON.parse(await fs.readFile(path.join(fixture.userData, 'drafts', receipt.test_project_uuid + '.json'))); + assert.equal(saved.format, 'rieke-renderer-draft'); assert.equal(saved.value.route.page, 'files'); + await start(); await page.getByRole('button', {name: new RegExp('^Open ' + projectName + ',')}).click(); + await page.getByRole('button', {name: 'Project files', exact: true}).waitFor({timeout: 90000}); + await chooseTestProfile(); + await page.waitForFunction(() => [...document.querySelectorAll('.nav-item.active')].some(item => item.textContent.includes('Project files')), undefined, {timeout: 10000}); + }); + await check('project draft identity mismatch requires visible preserved recovery', async () => { + await gracefulQuit(application, page); application = null; page = null; + const filename = path.join(fixture.userData, 'drafts', receipt.test_project_uuid + '.json'); + const saved = JSON.parse(await fs.readFile(filename, 'utf8')); + const corrupted = JSON.stringify({...saved, projectId: 'launcher'}); await fs.writeFile(filename, corrupted); + await start(); await page.getByRole('button', {name: new RegExp('^Open ' + projectName + ',')}).click(); + await page.getByRole('heading', {name: 'Saved view needs recovery', exact: true}).waitFor({timeout: 90000}); + assert.equal((await page.evaluate(() => window.riekeDesktop.quit())).ready, false); + assert.equal(await fs.readFile(filename, 'utf8'), corrupted); + await page.getByRole('button', {name: 'Start with a new view', exact: true}).click(); + await page.getByRole('button', {name: 'Project overview', exact: true}).waitFor({timeout: 30000}); + await chooseTestProfile(); + const backups = (await fs.readdir(path.dirname(filename))).filter(name => name.startsWith(receipt.test_project_uuid + '.corrupt-')); + assert.ok((await Promise.all(backups.map(name => fs.readFile(path.join(path.dirname(filename), name), 'utf8')))).includes(corrupted)); + return {project_identity_validated: true, mismatched_bytes_preserved: true, explicit_reset: true, + preserved_sha256: createHash('sha256').update(corrupted).digest('hex')}; + }); + await check('renderer crash enters recovery, preserves backend and requires recovery before quit', async () => { + const before = await ownedControl(fixture, 'health'); + deliberateCrash = true; + receipt.crash_test_method = 'Actual renderer crash; original stale Playwright target replaced by fresh CDP connection to the same isolated app; real recovery UI, bridge and backend health assertions'; + await application.evaluate(({BrowserWindow}) => {const target = BrowserWindow.getAllWindows()[0]; setTimeout(() => target.webContents.forcefullyCrashRenderer(), 100);}); + await delay(300); + // Attach a fresh software-test session to this isolated app's existing CDP + // endpoint. Pinned Playwright cannot revive its original crashed Page. + const port = Number((await fs.readFile(path.join(fixture.userData, 'DevToolsActivePort'), 'utf8')).split('\n')[0]); + recoveredBrowser = await chromium.connectOverCDP(`http://127.0.0.1:${port}`); + page = recoveredBrowser.contexts()[0].pages()[0]; + page.on('pageerror', error => receipt.failures.push({name: 'recovered-renderer-pageerror', message: error.message})); + await page.getByRole('heading', {name: 'Rieke OS recovery', exact: true}).waitFor({timeout: 15000}); + assert.equal((await ownedControl(fixture, 'health')).pid, before.pid); + const result = await page.evaluate(() => window.riekeDesktop.quit()); assert.equal(result.ready, false); + await page.screenshot({path: path.join(output, 'renderer-recovery.png')}); + await page.getByRole('button', {name: 'Retry startup', exact: true}).click(); + await page.getByRole('heading', {name: 'Your projects', exact: true}).waitFor({timeout: 30000}); + assert.equal((await ownedControl(fixture, 'health')).pid, before.pid); + deliberateCrash = false; + }); + await check('final orderly quit and packaged resource immutability', async () => { + await gracefulQuit(application, page); application = null; page = null; + await assert.rejects(fs.stat(path.join(fixture.userData, 'desktop-service.json')), {code: 'ENOENT'}); + await verifyResources(runtime, manifest.resources); + assert.equal(createHash('sha256').update(await fs.readFile(path.join(runtime, 'runtime-manifest.json'))).digest('hex'), receipt.manifest_sha256); + assert.equal(receipt.failures.length, 0, 'Unexpected renderer errors: ' + receipt.failures.map(item => item.message).join('; ')); + }); + receipt.completed = true; await writeReceipt(); console.log('Packaged UI E2E completed'); +} +main().catch(async error => { + process.exitCode = 1; await writeReceipt(); + if (page) await page.screenshot({path: path.join(output, 'failure.png')}).catch(() => {}); + if (application && page) { try {await gracefulQuit(application, page);} catch {console.error('Isolated app retained because orderly closure was not acknowledged.');} } + console.error(error.message); +}); diff --git a/desktop/e2e/testing-upgrade.e2e.cjs b/desktop/e2e/testing-upgrade.e2e.cjs new file mode 100644 index 0000000..bae0fac --- /dev/null +++ b/desktop/e2e/testing-upgrade.e2e.cjs @@ -0,0 +1,139 @@ +'use strict'; +// Real packaged updater/helper; only GitHub transport and macOS open are mapped +// to owned test boundaries. The source app, distribution and user app are read-only. +const assert=require('node:assert/strict'),fs=require('node:fs/promises'),nativeFs=require('node:fs'),path=require('node:path'),http=require('node:http'); +const {spawn}=require('node:child_process'),{createHash}=require('node:crypto'),asar=require('@electron/asar'); +const {createFixture,launch,gracefulQuit,ownedControl,run}=require('./helpers.cjs'); +const {bundleDigest}=require('../bootstrap.cjs'); +const {verifyResources}=require('../updater-validation.cjs'); +const output=path.resolve(__dirname,'../../docs/dev/desktop-testing-upgrade-e2e.json'); +const receipt={format:'rieke-packaged-testing-native-upgrade-e2e',version:1,production_ready:false,checks:[],failures:[], + seams:['Official GitHub HTTPS transport mapped to owned loopback server serving exact final ZIP/descriptor.', + 'Native helper macOS open boundary recorded instead of OS launch; installed app then starts with real Electron/WSGI in isolated HOME/profile.'], + limits:['Synthetic version-only prior app, not an authentic previously published 0.1.2 desktop release.','Unsigned local host only; no signed update or clean-machine qualification.'],user_app_untouched:true}; +let fixture,server,application;const requests={api:0,descriptor:0,archive:0}; +const delay=ms=>new Promise(resolve=>setTimeout(resolve,ms)); +async function write(){await fs.mkdir(path.dirname(output),{recursive:true});await fs.writeFile(output,JSON.stringify({...receipt,requests},null,2)+'\n');} +async function check(name,fn){const start=Date.now();try{const evidence=await fn();receipt.checks.push({name,passed:true,elapsed_ms:Date.now()-start,evidence});console.log('PASS '+name);}catch(error){receipt.failures.push({name,message:error.message});await write();throw error;}await write();} +const WRAPPER=String.raw` +'use strict'; +const fs=require('node:fs'),path=require('node:path'),{promisify}=require('node:util'); +const realRun=promisify(require('node:child_process').execFile); +const config=JSON.parse(fs.readFileSync(process.argv[2],'utf8')); +const helper=require(path.join(config.bundle,'Contents/Resources/app.asar/testing-install.cjs')); +let opens=0; +helper.applyTestingInstall({receiptPath:process.argv[3],run:async(exe,args,options)=>{ + if(exe!=='/usr/bin/open')return realRun(exe,args,options); + opens++;fs.appendFileSync(config.openLog,JSON.stringify({phase:config.phase,args})+'\n',{mode:0o600}); + if(config.fail_first_open&&opens===1)throw new Error('Owned test simulates macOS refusing the candidate launch'); + return {stdout:'',stderr:''}; +}}).catch(error=>{fs.writeFileSync(process.argv[3]+'.result.json',JSON.stringify({state:'Deferred',error_type:error.name,message:error.message}));process.exitCode=1;}); +`; +const DRIVER=String.raw` +'use strict'; +const fs=require('node:fs'),path=require('node:path'),http=require('node:http'),{spawn}=require('node:child_process'); +const config=JSON.parse(fs.readFileSync(process.argv[2],'utf8')); +const manifest=JSON.parse(fs.readFileSync(path.join(config.bundle,'Contents/Resources/runtime/runtime-manifest.json'),'utf8')); +const packaged=path.join(config.bundle,'Contents/Resources/app.asar'); +const helper=require(path.join(packaged,'testing-install.cjs')); +const {createTestingUpdateCoordinator}=require(path.join(packaged,'testing-updater.cjs')); +const statuses=[];let coordinator,handoff,authorized=false; +const app={isPackaged:true,getPath:name=>name==='exe'?process.execPath:config.userData,quit(){ + coordinator?.stop();setTimeout(()=>{fs.writeFileSync(config.driverResult,JSON.stringify({phase:config.phase,authorized,statuses,handoff}),{mode:0o600});process.exit(0);},50); +}}; +const transport=url=>{ + const route=url==='https://api.github.com/repos/maxwellsdm1867/Rieke-OS/releases?per_page=100&page=1'?'/api': + url===config.descriptorURL?'/descriptor':url===config.archiveURL?'/archive':null; + if(!route)return Promise.reject(new Error('Unexpected official release URL')); + return new Promise((resolve,reject)=>http.get(config.base+route,response=>resolve({statusCode:response.statusCode,headers:response.headers,body:response})).on('error',reject)); +}; +const spawnHelper=(exe,args,options)=>spawn(exe,[config.wrapper,process.argv[2],args[2]],options); +(async()=>{ + const authorizeQuit=()=>{authorized=true;}; + if(config.phase==='restore'){ + handoff=await helper.restoreTestingPriorBundle({app,manifest,prepareQuit:async()=>({ready:true}),authorizeQuit,spawnHelper}); + }else{ + coordinator=createTestingUpdateCoordinator({app,manifest,distribution:require(path.join(packaged,'distribution.json')),transport, + publishStatus:status=>{if(statuses.at(-1)!==status.state)statuses.push(status.state);},prepareQuit:async()=>({ready:true}),authorizeQuit, + installHelper:async options=>{handoff=await helper.launchTestingInstall({...options,spawnHelper});return handoff;}}); + await coordinator.start();if(!['Available','Ready'].includes(coordinator.getStatus().state))throw new Error('Official fixture did not offer update'); + await coordinator.download();if(coordinator.getStatus().state!=='Ready')throw new Error('Real candidate validation did not become Ready'); + const result=await coordinator.installPrepared();if(!result.installing)throw new Error(result.reason||'Native install did not hand off'); + } +})().catch(error=>{coordinator?.stop();fs.writeFileSync(config.driverResult,JSON.stringify({error:error.message,statuses}),{mode:0o600});process.exitCode=1;}); +`; +async function versionPrior(){ + const runtime=path.join(fixture.bundle,'Contents/Resources/runtime'),file=path.join(runtime,'runtime-manifest.json'); + const manifest=JSON.parse(await fs.readFile(file));manifest.application_version='0.1.2'; + for(const name of Object.keys(manifest.resources).filter(name=>name.endsWith('/rieke-release.json'))){ + const target=path.join(runtime,name),release=JSON.parse(await fs.readFile(target));release.version='0.1.2';const data=Buffer.from(JSON.stringify(release,null,2)+'\n');await fs.writeFile(target,data); + manifest.resources[name]={...manifest.resources[name],sha256:createHash('sha256').update(data).digest('hex'),size:data.length}; + } + await fs.writeFile(file,JSON.stringify(manifest,null,2)+'\n'); + const archive=path.join(fixture.bundle,'Contents/Resources/app.asar'),directory=path.join(fixture.root,'prior-asar');asar.extractAll(archive,directory); + const packageFile=path.join(directory,'package.json'),pack=JSON.parse(await fs.readFile(packageFile));pack.version='0.1.2';await fs.writeFile(packageFile,JSON.stringify(pack,null,2)+'\n'); + await asar.createPackage(directory,archive);asar.uncacheAll(); + const plist=path.join(fixture.bundle,'Contents/Info.plist'); + for(const field of ['CFBundleShortVersionString','CFBundleVersion'])await run('/usr/libexec/PlistBuddy',['-c',`Set :${field} 0.1.2`,plist]); + await run('/usr/libexec/PlistBuddy',['-c',`Set :ElectronAsarIntegrity:Resources/app.asar:hash ${createHash('sha256').update(asar.getRawHeader(archive).headerString).digest('hex')}`,plist]); + await run('/usr/bin/codesign',['--force','--sign','-','--entitlements',path.resolve(__dirname,'../entitlements.mac.plist'),fixture.bundle]); + await run('/usr/bin/codesign',['--verify','--deep','--strict',fixture.bundle]);await verifyResources(runtime,manifest.resources); +} +async function phase(phase,config){ + const configFile=path.join(fixture.root,phase+'.json'),driverResult=path.join(fixture.root,phase+'-driver.json'); + await fs.writeFile(configFile,JSON.stringify({...config,phase,driverResult,fail_first_open:phase==='rollback'}),{mode:0o600}); + const log=await fs.open(path.join(fixture.root,phase+'.log'),'w'); + const child=spawn(fixture.executable,[config.driver,configFile],{cwd:fixture.root,env:{HOME:fixture.home,TMPDIR:fixture.root,PATH:'/usr/bin:/bin',LANG:'en_US.UTF-8',ELECTRON_RUN_AS_NODE:'1',PYTHONDONTWRITEBYTECODE:'1'},stdio:['ignore',log.fd,log.fd]}); + const exit=await new Promise((resolve,reject)=>{child.once('error',reject);child.once('exit',resolve);});await log.close(); + const driver=JSON.parse(await fs.readFile(driverResult));assert.equal(exit,0,JSON.stringify(driver));assert.equal(driver.authorized,true);assert.ok(driver.handoff?.resultPath); + let outcome;for(let n=0;n<600;n++){try{outcome=JSON.parse(await fs.readFile(driver.handoff.resultPath));break;}catch{await delay(500);}} + assert.ok(outcome,'Native helper result missing after exact current process exit'); + return {driver,outcome}; +} +async function startup(version){ + const launched=await launch(fixture);application=launched.application; + await launched.page.getByRole('heading',{name:'Your projects',exact:true}).waitFor({timeout:90000}); + const health=await ownedControl(fixture,'health');assert.equal(health.application_version,version); + await gracefulQuit(application,launched.page);application=null; + return{application_version:health.application_version,owned_wsgi_ready:true,real_electron_started:true,isolated_home_and_profile:true,orderly_shutdown:true}; +} +async function main(){ + fixture=await createFixture({reuse:false}); + const published=path.resolve(__dirname,'../dist/mac-arm64/Rieke OS.app'),zip=path.resolve(__dirname,'../dist/Rieke-OS-0.1.3-arm64.zip'); + const sourceManifest=await fs.readFile(path.join(published,'Contents/Resources/runtime/runtime-manifest.json')); + assert.equal(JSON.parse(sourceManifest).application_version,'0.1.3');receipt.runtime_manifest_sha256=createHash('sha256').update(sourceManifest).digest('hex'); + receipt.asar_sha256=createHash('sha256').update(await fs.readFile(path.join(published,'Contents/Resources/app.asar'))).digest('hex'); + const descriptorBytes=await fs.readFile(path.resolve(__dirname,'../dist/desktop-release.json')),descriptor=JSON.parse(descriptorBytes);receipt.archive_sha256=descriptor.archive.sha256; + await versionPrior();const priorDigest=await bundleDigest(fixture.bundle);receipt.prior_fixture_bundle_sha256=priorDigest; + const tag='desktop-test-v0.1.3',baseURL=`https://github.com/maxwellsdm1867/Rieke-OS/releases/download/${tag}/`; + const releases=Buffer.from(JSON.stringify([{draft:false,prerelease:true,tag_name:tag,assets:[{name:'desktop-release.json',size:descriptorBytes.length,browser_download_url:baseURL+'desktop-release.json'},{name:descriptor.archive.filename,size:descriptor.archive.size,browser_download_url:baseURL+descriptor.archive.filename}]}])); + server=http.createServer((request,response)=>{ + const resource=request.url==='/api'?releases:request.url==='/descriptor'?descriptorBytes:null; + if(resource){requests[request.url==='/api'?'api':'descriptor']++;response.writeHead(200,{'content-length':resource.length});response.end(resource);} + else if(request.url==='/archive'){requests.archive++;response.writeHead(200,{'content-length':descriptor.archive.size});nativeFs.createReadStream(zip).pipe(response);} + else{response.writeHead(404);response.end();} + });await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve)); + const driver=path.join(fixture.root,'driver.cjs'),wrapper=path.join(fixture.root,'owned-open-wrapper.cjs'),openLog=path.join(fixture.root,'open.jsonl');await fs.writeFile(driver,DRIVER);await fs.writeFile(wrapper,WRAPPER); + const config={bundle:fixture.bundle,userData:fixture.userData,driver,wrapper,openLog,base:`http://127.0.0.1:${server.address().port}`,descriptorURL:baseURL+'desktop-release.json',archiveURL:baseURL+descriptor.archive.filename}; + await check('real ZIP updater validates and native helper waits current PID exit before complete 0.1.3 installation',async()=>{ + const {driver,outcome}=await phase('update',config);assert.equal(outcome.state,'Installed');assert.equal(outcome.version,'0.1.3'); + assert.equal(await bundleDigest(fixture.bundle),await bundleDigest(published));assert.equal(await bundleDigest(path.join(path.dirname(fixture.bundle),'.Rieke OS.previous.app')),priorDigest); + return{current_process_ready_handshake:true,authorized_only_after_helper_ready:true,exact_current_process_exited:true,complete_target_matches_final_bundle:true,previous_complete_bundle_retained:true,statuses:driver.statuses}; + }); + await check('actual updated Electron and WSGI start in preserved isolated profile and stop cleanly',()=>startup('0.1.3')); + await check('controlled Restore installs only verified retained prior bundle without archive download',async()=>{ + const before=requests.archive,{outcome}=await phase('restore',config);assert.equal(outcome.state,'Restored');assert.equal(outcome.version,'0.1.2');assert.equal(await bundleDigest(fixture.bundle),priorDigest);assert.equal(requests.archive,before); + return{verified_previous_restored:true,archive_download_not_required:true,profile_preserved:true}; + }); + await check('macOS launch refusal triggers complete previous-app rollback with profile unchanged',async()=>{ + const {outcome}=await phase('rollback',config);assert.equal(outcome.state,'Restored');assert.equal(outcome.version,'0.1.2');assert.equal(await bundleDigest(fixture.bundle),priorDigest); + return{candidate_launch_refusal_simulated_at_only_open_boundary:true,exact_previous_restored:true,failed_candidate_retained:true}; + }); + await check('restored Electron and WSGI still start and stop without dependency installation',()=>startup('0.1.2')); + const opens=(await fs.readFile(openLog,'utf8')).trim().split('\n').map(line=>JSON.parse(line)); + assert.ok(opens.every(entry=>entry.args.includes(fixture.bundle)&&entry.args.includes(`--user-data-dir=${fixture.userData}`)));receipt.open_boundary_calls=opens.length;receipt.profile_continuity_verified=true; + assert.equal(createHash('sha256').update(await fs.readFile(path.join(published,'Contents/Resources/runtime/runtime-manifest.json'))).digest('hex'),receipt.runtime_manifest_sha256); + assert.equal(createHash('sha256').update(await fs.readFile(path.join(published,'Contents/Resources/app.asar'))).digest('hex'),receipt.asar_sha256); + receipt.passed=true;await write();await new Promise(resolve=>server.close(resolve));server=null;await fs.rm(fixture.root,{recursive:true,force:true});console.log('Native testing upgrade receipt: '+output); +} +main().catch(async error=>{console.error(error.stack);receipt.failures.push({name:'native-testing-upgrade-suite',message:error.message});receipt.passed=false;await write();server?.close();if(fixture)console.error('Owned diagnostics retained: '+fixture.root);process.exitCode=1;}); diff --git a/desktop/e2e/toolbar-preview.cjs b/desktop/e2e/toolbar-preview.cjs new file mode 100644 index 0000000..7a113b9 --- /dev/null +++ b/desktop/e2e/toolbar-preview.cjs @@ -0,0 +1,50 @@ +'use strict'; +const assert = require('node:assert/strict'); +const fs = require('node:fs/promises'), path = require('node:path'); +const {createHash} = require('node:crypto'); +const {createFixture, launch, gracefulQuit} = require('./helpers.cjs'); +const {verifyResources} = require('../updater-validation.cjs'); +const output = path.resolve(__dirname, '../../docs/dev/desktop-ui-e2e'); +(async () => { + const fixture = await createFixture(); let application, page; + const manifestBytes = await fs.readFile(path.join(fixture.bundle, 'Contents/Resources/runtime/runtime-manifest.json')); + const manifest = JSON.parse(manifestBytes); + try { + ({application,page} = await launch(fixture)); + await page.getByRole('heading', {name:'Your projects', exact:true}).waitFor({timeout:90000}); + const previous = JSON.parse(await fs.readFile(path.join(output, 'before-toolbar-fit-fix.json'))); + await page.getByRole('button', {name:new RegExp('^Open Electron lifecycle fixture ' + previous.run_id + ',')}).click(); + await page.getByRole('button', {name:'Project overview',exact:true}).waitFor({timeout:90000}); + const profile = page.getByRole('dialog', {name:'Tag author',exact:true}); + if(await profile.waitFor({state:'visible',timeout:3000}).then(()=>true).catch(()=>false)) { + await profile.getByRole('button', {name:'Electron E2E',exact:true}).first().click(); await profile.waitFor({state:'hidden'}); + } + const source = await fs.readFile(path.resolve(__dirname,'../../workspace-app/src/styles.css'),'utf8'); + const marker = '/* Keep the app mark visible as the scientific toolbar gets narrower. */'; + assert.ok(source.includes(marker)); const css = source.slice(source.indexOf(marker)); + // The packaged CSP explicitly allows inline styles. This preview leaves + // that policy, the app bundle and all backend resources unchanged. + assert.ok(await page.evaluate(css => {const style=document.createElement('style');style.textContent=css;document.head.append(style);return style.sheet?.cssRules.length>0;},css)); + const measurements = []; + for(const width of [1440,960]) { + await application.evaluate(({BrowserWindow},width)=>BrowserWindow.getAllWindows()[0].setContentSize(width,900),width); + await page.waitForFunction(width=>innerWidth===width,width); + const geometry = await page.evaluate(()=>{ + const icon=document.querySelector('.header-app-icon'),header=document.querySelector('.app-header'); + const rect=node=>{const r=node.getBoundingClientRect();return {left:r.left,right:r.right,top:r.top,bottom:r.bottom};}; + return {width:innerWidth,naturalWidth:icon.naturalWidth,icon:rect(icon),header:rect(header),controls:[...header.children] + .filter(node=>node!==icon&&!node.classList.contains('spacer')&&node.getClientRects().length).map(node=>({className:node.className,...rect(node)}))}; + }); + await page.screenshot({path:path.join(output,`toolbar-preview-${width}.png`)}); + assert.ok(geometry.naturalWidth>0); assert.ok(geometry.icon.right<=geometry.header.right&&geometry.icon.right<=width); + for(const c of geometry.controls) assert.ok(!(c.leftgeometry.icon.left&&c.topgeometry.icon.top)); + measurements.push(geometry); + } + await gracefulQuit(application,page); application=null;page=null; + await verifyResources(path.join(fixture.bundle,'Contents/Resources/runtime'),manifest.resources); + const receipt={format:'rieke-toolbar-css-preview',version:1,passed:true,final_packaged_qualification:false, + method:'Exact prior disposable packaged fixture; DOM-only inline CSS allowed by existing CSP; no bundle or backend mutation', + source_manifest_sha256:createHash('sha256').update(manifestBytes).digest('hex'),preview_css_sha256:createHash('sha256').update(css).digest('hex'),measurements}; + await fs.writeFile(path.join(output,'toolbar-preview.json'),JSON.stringify(receipt,null,2)+'\n');console.log(JSON.stringify(receipt)); + } finally {if(application&&page) await gracefulQuit(application,page);} +})().catch(error=>{console.error(error.message);process.exitCode=1;}); diff --git a/desktop/entitlements.mac.plist b/desktop/entitlements.mac.plist new file mode 100644 index 0000000..bda591d --- /dev/null +++ b/desktop/entitlements.mac.plist @@ -0,0 +1,5 @@ + + + +com.apple.security.cs.allow-jit + diff --git a/desktop/icon.png b/desktop/icon.png new file mode 100644 index 0000000..6685dbf Binary files /dev/null and b/desktop/icon.png differ diff --git a/desktop/main.cjs b/desktop/main.cjs new file mode 100644 index 0000000..d341725 --- /dev/null +++ b/desktop/main.cjs @@ -0,0 +1,222 @@ +'use strict'; +const {app, BrowserWindow, ipcMain, dialog, session, shell, Menu, powerMonitor} = require('electron'); +const path = require('node:path'); +const os = require('node:os'); +const {execFile} = require('node:child_process'); +const {promisify} = require('node:util'); +const {ServiceSupervisor, matchesHealth} = require('./supervisor.cjs'); +const {validateSender, approvedReleaseURL, isOwnedURL} = require('./security.cjs'); +const {enclosingApp, installCompleteBundle} = require('./bootstrap.cjs'); +const {DraftBarrier} = require('./draft-barrier.cjs'); +const {DraftStore} = require('./draft-store.cjs'); +const {distributionPolicy} = require('./distribution.cjs'); +const distribution = distributionPolicy(require('./distribution.json')); +app.enableSandbox(); +app.setName('Rieke OS'); +const windows = new Set(); +const scientificWindows = new Set(); +const recoveryPage = path.join(__dirname, 'recovery.html'); +const sourceApp = enclosingApp(process.execPath); +const destination = path.join(os.homedir(), 'Applications', 'Rieke OS.app'); +const bootstrap = app.isPackaged && process.platform === 'darwin' && sourceApp !== destination; +const installedUserData = app.getPath('userData'); +if (bootstrap) { + // A downloaded installer must be able to explain why a running installed app + // blocks replacement instead of silently forwarding its launch to that app. + const installerState = path.join(app.getPath('userData'), 'installer'); + require('node:fs').mkdirSync(installerState, {recursive:true,mode:0o700}); + app.setPath('userData', installerState); +} +let supervisor, coordinator, quitAuthorized = false, quitInProgress = false, startupInProgress = false; +let draftStore; +let lifecycleStatus = {state: 'Starting', title: 'Starting Rieke OS', message: 'Verifying the complete app and its private runtime.'}; +const draftBarrier = new DraftBarrier(); +function broadcast(value) { + for (const window of windows) if (!window.isDestroyed()) window.webContents.send('desktop:status-changed', value); +} +function status() { return lifecycleStatus.state === 'Running' ? (coordinator?.getStatus() || {state: 'Current', installed_version: app.getVersion()}) : lifecycleStatus; } +function recovery(message, detail = '') { + lifecycleStatus = {state: 'Recovery', channel:distribution.channel, title: 'Rieke OS recovery', message, detail}; broadcast(lifecycleStatus); + for (const window of windows) if (!window.isDestroyed()) window.loadFile(recoveryPage).catch(() => {}); +} +async function acknowledgeDrafts() { + return draftBarrier.prepare(scientificWindows); +} +async function prepareQuit() { + const drafts = await acknowledgeDrafts(); if (!drafts.ready) return drafts; + return supervisor ? supervisor.drain() : {ready: true}; +} +async function orderlyQuit() { + if (quitInProgress) return {ready: false, reason: 'Quit preparation is already in progress'}; + quitInProgress = true; + try { + if (distribution.channel !== 'unsigned-testing' && coordinator?.getStatus().state === 'Ready') { + const result = await coordinator.installPrepared(); + if (result.installing) return result; + if (!result.ready) { broadcast({...status(), message: result.reason}); return result; } + } + const result = await prepareQuit(); + if (!result.ready) { broadcast({...status(), message: result.reason}); return result; } + quitAuthorized = true; coordinator?.stop(); app.quit(); return result; + } finally { quitInProgress = false; } +} +function createWindow() { + const window = new BrowserWindow({width: 1440, height: 960, minWidth: 960, minHeight: 650, + title: 'Rieke OS', backgroundColor: '#f4f5f3', show: false, + webPreferences: {preload: path.join(__dirname, 'preload.cjs'), contextIsolation: true, + sandbox: true, nodeIntegration: false, nodeIntegrationInWorker: false, + webSecurity: true, allowRunningInsecureContent: false, webviewTag: false, spellcheck: false, + partition: 'rieke-desktop'}}); + windows.add(window); + window.once('ready-to-show', () => window.show()); + window.webContents.setWindowOpenHandler(() => ({action: 'deny'})); + window.webContents.on('will-attach-webview', event => event.preventDefault()); + window.webContents.on('will-navigate', (event, url) => { + if (isOwnedURL(url, null, [recoveryPage])) return; + event.preventDefault(); + if (supervisor?.ready) supervisor.authorizeProjectURL(url).then(allowed => { + if (allowed && !window.isDestroyed()) window.loadURL(url); + }).catch(() => recovery('A project service failed ownership verification.')); + }); + window.webContents.on('will-redirect', (event, url) => { + if (!isOwnedURL(url, supervisor?.origins, [recoveryPage])) event.preventDefault(); + }); + window.webContents.on('render-process-gone', () => { window.draftUnavailable = scientificWindows.has(window); recovery('The scientific window stopped. Restore the window to acknowledge drafts before shutdown.'); }); + window.on('close', event => { if (!quitAuthorized) { event.preventDefault(); void orderlyQuit(); } }); + window.on('closed', () => { windows.delete(window); scientificWindows.delete(window); }); + window.loadFile(recoveryPage); return window; +} +function configureSession() { + const ownedSession = session.fromPartition('rieke-desktop'); + ownedSession.setPermissionRequestHandler((_contents, _permission, callback) => callback(false)); + ownedSession.setPermissionCheckHandler(() => false); + ownedSession.webRequest.onBeforeRequest((details, callback) => { + const owned = [...windows].some(win => !win.isDestroyed() && win.webContents.id === details.webContentsId); + const localAsset = details.url.startsWith('file:') && (() => { + try { return require('node:url').fileURLToPath(details.url).startsWith(__dirname + path.sep); } catch { return false; } + })(); + callback({cancel: !owned || (!localAsset && !isOwnedURL(details.url, supervisor?.origins))}); + }); + ownedSession.webRequest.onBeforeSendHeaders((details, callback) => { + const headers = {...details.requestHeaders}; + for (const key of Object.keys(headers)) if (['x-rieke-desktop-capability', 'x-rieke-desktop-session'].includes(key.toLowerCase())) delete headers[key]; + if (supervisor && isOwnedURL(details.url, supervisor.origins) && [...windows].some(win => !win.isDestroyed() && win.webContents.id === details.webContentsId)) + headers['X-Rieke-Desktop-Session'] = supervisor.rendererCapability; + callback({requestHeaders: headers}); + }); + ownedSession.webRequest.onHeadersReceived((details, callback) => { + const headers = {...details.responseHeaders}; + if (isOwnedURL(details.url, supervisor?.origins)) { + headers['Content-Security-Policy'] = ["default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; font-src 'self'; object-src 'none'; frame-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'"]; + headers['X-Content-Type-Options'] = ['nosniff']; + } + callback({responseHeaders: headers}); + }); + ownedSession.on('will-download', (event, item, contents) => { + if (![...windows].some(win => win.webContents === contents) || !isOwnedURL(item.getURL(), supervisor?.origins)) { event.preventDefault(); return; } + const filename = path.basename(item.getFilename()).replace(/[\x00-\x1f]/g, '_'); + item.setSaveDialogOptions({title: 'Save export', defaultPath: filename}); + }); +} +async function startScientificUI() { + if (startupInProgress) return; + startupInProgress = true; + try { + let origin; + if (supervisor.child && !supervisor.exited) { + const health = await supervisor.api('/api/desktop/health'); + if (!matchesHealth(health, supervisor.expectedHealth())) throw new Error('Existing backend is not ready for recovery'); + origin = supervisor.origin; supervisor.ready = true; supervisor.origins.add(origin); + } else origin = await supervisor.start(); + if (!coordinator) { + const createUpdateCoordinator = distribution.channel === 'unsigned-testing' + ? require('./testing-updater.cjs').createTestingUpdateCoordinator + : require('./updater.cjs').createUpdateCoordinator; + coordinator = createUpdateCoordinator({app, publishStatus: broadcast, prepareQuit, + authorizeQuit: () => { quitAuthorized = true; }, revokeQuit: () => { quitAuthorized = false; }, + onInstallationFailure: () => { scientificWindows.clear(); recovery('Native update installation failed. Restart the installed backend or restore the verified previous app.'); }, + manifest: supervisor.manifest, distribution}); + coordinator.start().catch(() => broadcast({state:'Deferred',channel:distribution.channel,message:'Update check unavailable. The installed app remains usable.'})); + } + lifecycleStatus = {state: 'Running'}; + for (const window of windows) { + await window.loadURL(origin); window.draftUnavailable = false; scientificWindows.add(window); + } + broadcast(status()); + } catch (error) { recovery('The packaged scientific backend could not start. Projects have not been opened.', error.message); } + finally { startupInProgress = false; } +} +function registerIPC() { + const handle = (channel, action) => ipcMain.handle(channel, async (event, payload) => { + const window = validateSender(event, windows, supervisor?.origins, [recoveryPage]); return action(payload, window); + }); + const noPayload = (channel, action) => handle(channel, (payload, window) => { + if (payload !== undefined) throw new TypeError('This desktop operation accepts no payload'); + return action(window); + }); + noPayload('desktop:status', () => status()); + noPayload('desktop:check-updates', () => coordinator ? coordinator.check() : status()); + noPayload('desktop:download-update', () => { + if (!coordinator?.download) throw new Error('Update download is unavailable for this installation.'); + return coordinator.download(); + }); + noPayload('desktop:restart-to-update', () => { + if (!coordinator) throw new Error('No prepared update is available.'); + return coordinator.installPrepared(); + }); + noPayload('desktop:quit', () => orderlyQuit()); + noPayload('desktop:retry-startup', () => { if (bootstrap) throw new Error('Install the complete app before starting projects'); return startScientificUI(); }); + handle('desktop:restore-previous', async payload => { + if (payload !== undefined || lifecycleStatus.state !== 'Recovery') throw new Error('Verified restoration is available only from recovery'); + const restorePriorBundle = distribution.channel === 'unsigned-testing' + ? require('./testing-install.cjs').restoreTestingPriorBundle + : require('./update-recovery.cjs').restorePriorBundle; + const manifest = supervisor.manifest || await supervisor.loadManifest(); + return restorePriorBundle({app, prepareQuit, authorizeQuit: () => { quitAuthorized = true; }, manifest}); + }); + handle('desktop:drafts-ack', (payload, window) => { + return draftBarrier.acknowledge(payload, window); + }); + handle('desktop:save-draft', async payload => { + return draftStore.save(payload); + }); + handle('desktop:load-draft', async projectId => { + return draftStore.load(projectId); + }); + handle('desktop:reset-draft', projectId => draftStore.reset(projectId)); + noPayload('desktop:choose-project-folder', async window => { + const result = await dialog.showOpenDialog(window, {properties: ['openDirectory', 'createDirectory'], title: 'Choose project folder'}); + return result.canceled ? null : result.filePaths[0]; + }); + handle('desktop:open-release-notes', async url => { + if (!approvedReleaseURL(url)) throw new TypeError('Only official HTTPS release notes may be opened'); + await shell.openExternal(url); return {opened: true}; + }); + noPayload('desktop:install-and-open', async () => { + if (!bootstrap || supervisor?.child) throw new Error('Install action is available only before backend startup'); + const result = await installCompleteBundle({source: sourceApp, destination, distribution}); + app.releaseSingleInstanceLock(); + await promisify(execFile)('/usr/bin/open', ['-n', '-a', result.destination, + '--env', `HOME=${os.homedir()}`, '--args', `--user-data-dir=${installedUserData}`]); + quitAuthorized = true; app.quit(); return {installed: true}; + }); +} +if (!app.requestSingleInstanceLock()) app.quit(); +else { + app.on('second-instance', () => { const window = [...windows][0]; if (window) { if (window.isMinimized()) window.restore(); window.show(); window.focus(); } }); + app.on('before-quit', event => { if (!quitAuthorized) { event.preventDefault(); void orderlyQuit(); } }); + app.on('window-all-closed', () => { if (quitAuthorized) app.quit(); }); + app.whenReady().then(async () => { + draftStore = new DraftStore(app.getPath('userData')); + supervisor = new ServiceSupervisor({resourcesPath: app.isPackaged ? process.resourcesPath : path.join(__dirname, 'build'), + userData: app.getPath('userData'), appVersion: app.getVersion(), onFailure: recovery}); + configureSession(); registerIPC(); createWindow(); + powerMonitor.on('shutdown', event => { if (!quitAuthorized) { event.preventDefault(); void orderlyQuit(); } }); + Menu.setApplicationMenu(Menu.buildFromTemplate([{label: 'Rieke OS', submenu: [{role: 'about'}, {type: 'separator'}, + {label: 'Check for Updates', click: () => coordinator?.check()}, {type: 'separator'}, {label: 'Quit Rieke OS', accelerator: 'CommandOrControl+Q', click: () => orderlyQuit()}]}, + {label: 'Edit', submenu: [{role: 'undo'}, {role: 'redo'}, {type: 'separator'}, {role: 'cut'}, {role: 'copy'}, {role: 'paste'}, {role: 'selectAll'}]}, + {label: 'Window', submenu: [{role: 'minimize'}, {role: 'zoom'}]}])); + if (bootstrap) { lifecycleStatus = {state: 'Bootstrap', channel:distribution.channel, title: 'Install Rieke OS', message: 'Install this complete app in your Applications folder and open it.', detail: distribution.channel === 'unsigned-testing' ? 'Unsigned testing release. Install a copy downloaded from the official Rieke OS GitHub release. macOS may require a one-time Open Anyway approval in Privacy & Security. Existing projects stay in their selected folders.' : 'The downloaded app and installed copy must pass Developer ID signature verification. Existing projects stay in their selected folders.'}; broadcast(lifecycleStatus); } + else await startScientificUI(); + }).catch(error => { console.error('Desktop startup failed:', error.name); app.exit(1); }); +} diff --git a/desktop/native-license-sources.json b/desktop/native-license-sources.json new file mode 100644 index 0000000..514afc2 --- /dev/null +++ b/desktop/native-license-sources.json @@ -0,0 +1,42 @@ +{ + "format": "rieke-native-license-sources", + "version": 1, + "sources": [ + { + "package": "mysql-server", + "applies_to": ["mysql-server", "mysql-client", "mysql-common"], + "version": "8.4.2", + "url": "https://raw.githubusercontent.com/mysql/mysql-server/mysql-8.4.2/LICENSE", + "file": "mysql-8.4.2-LICENSE.txt", + "sha256": "2717175c705374f2a95d4dba0f99382e5a4a0190d3de769626c72b9351b18132" + }, + { + "package": "libabseil", + "version": "20240116.2", + "url": "https://raw.githubusercontent.com/abseil/abseil-cpp/20240116.2/LICENSE", + "file": "abseil-20240116.2-LICENSE.txt", + "sha256": "c79a7fea0e3cac04cd43f20e7b648e5a0ff8fa5344e644b0ee09ca1162b62747" + }, + { + "package": "libprotobuf", + "version": "4.25.3", + "url": "https://raw.githubusercontent.com/protocolbuffers/protobuf/v25.3/LICENSE", + "file": "protobuf-25.3-LICENSE.txt", + "sha256": "6e5e117324afd944dcf67f36cf329843bc1a92229a8cd9bb573d7a83130fea7d" + }, + { + "package": "lz4-c", + "version": "1.9.4", + "url": "https://raw.githubusercontent.com/lz4/lz4/v1.9.4/lib/LICENSE", + "file": "lz4-1.9.4-library-LICENSE.txt", + "sha256": "8b58c446121a109ccf32edc094bba3010a3d85e4ee3702950db55e4d3e87736c" + }, + { + "package": "lz4-c", + "version": "1.9.4", + "url": "https://raw.githubusercontent.com/lz4/lz4/v1.9.4/programs/COPYING", + "file": "lz4-1.9.4-programs-COPYING.txt", + "sha256": "8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643" + } + ] +} diff --git a/desktop/package-lock.json b/desktop/package-lock.json new file mode 100644 index 0000000..f1ddf78 --- /dev/null +++ b/desktop/package-lock.json @@ -0,0 +1,3659 @@ +{ + "name": "rieke-os-desktop", + "version": "0.1.3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "rieke-os-desktop", + "version": "0.1.3", + "dependencies": { + "electron-updater": "6.8.9" + }, + "devDependencies": { + "electron": "44.5.0", + "electron-builder": "26.15.3", + "playwright": "1.63.0" + } + }, + "node_modules/@electron-internal/extract-zip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.5.tgz", + "integrity": "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/get": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.1.0.tgz", + "integrity": "sha512-3kSBtG8ObcTVfXanm5vVJ6UnBLEVmVsRk1M+vGqCuMBV+XLCbJYuWQful+yIy0GQDsSlK0kHEriEHn7SPk4EnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^3.0.0", + "graceful-fs": "^4.2.11", + "progress": "^2.0.3", + "semver": "^7.6.3", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=22.12.0" + }, + "optionalDependencies": { + "undici": "^7.24.4" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/rebuild": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.2.0.tgz", + "integrity": "sha512-RKL/O+jGoXJMxrx/5771y1n0xTKmFuOYGO3gMmwypBM6rsH0kou0mswwdXA2JrhIkE4xyC7v9vGk0n6NPzgOxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.1.1", + "node-abi": "^4.2.0", + "node-api-version": "^0.2.1", + "node-gyp": "^12.2.0", + "read-binary-file-arch": "^1.0.6" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.3.1", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", + "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", + "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@noble/hashes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", + "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.10.0.tgz", + "integrity": "sha512-GhokD41lV4gQrrLYm3wCkHfBOnJrnhDMgt4XeMW8gzfE1UdJqIuSwsE+ggf82XBjUXRJylcm+KIGQFa4utIVLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.7.1.tgz", + "integrity": "sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/json-schema": "^1.1.12", + "@peculiar/utils": "^2.0.2", + "tslib": "^2.8.1", + "webcrypto-core": "^1.9.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.19.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.0.tgz", + "integrity": "sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/app-builder-lib": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.15.3.tgz", + "integrity": "sha512-2VnyWkqsP5v5XbBhL3tD5Syx8iNPBYsoU7kY4S2fz7wg8Rj/nztWKCUzGKaFRTv0Xwf3/H058CR1Kvtd/3lRow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "3.4.1", + "@electron/fuses": "^1.8.0", + "@electron/get": "^3.0.0", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "^4.0.4", + "@electron/universal": "2.0.3", + "@malept/flatpak-bundler": "^0.4.0", + "@noble/hashes": "^2.2.0", + "@peculiar/webcrypto": "^1.7.1", + "@types/fs-extra": "9.0.13", + "ajv": "^8.18.0", + "asn1js": "^3.0.10", + "async-exit-hook": "^2.0.1", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", + "chromium-pickle-js": "^0.2.0", + "ci-info": "4.3.1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "26.15.3", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.2.5", + "pkijs": "^3.4.0", + "plist": "3.1.0", + "proper-lockfile": "^4.1.2", + "resedit": "^1.7.0", + "semver": "~7.7.3", + "tar": "^7.5.7", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0", + "unzipper": "^0.12.3", + "which": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "26.15.3", + "electron-builder-squirrel-windows": "26.15.3" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", + "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/app-builder-lib/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/app-builder-lib/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/asn1js": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.15.3.tgz", + "integrity": "sha512-q2hn7Mbo2nFNkVekPiHFx6Nfo3hURmES3tfBn+k5Pqxl2RkmP3QGqZUhH/q9Pch/4G05NRhPjDlVj1O8q4Txvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "builder-util-runtime": "9.7.0", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.6", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.7.0.tgz", + "integrity": "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dmg-builder": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.15.3.tgz", + "integrity": "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "44.5.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-44.5.0.tgz", + "integrity": "sha512-gVUJ6DZcRY80Alh/krc7uwjjCfxjZ3T2suvpBmHsN6zE4ShAc4vzG14kbMgT+ZteaPLddoKg4Pie0CjDdIDdyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-internal/extract-zip": "^1.0.1", + "@electron/get": "^5.0.0", + "@types/node": "^24.9.0" + }, + "bin": { + "electron": "cli.js", + "install-electron": "install.js" + }, + "engines": { + "node": ">= 22.12.0" + } + }, + "node_modules/electron-builder": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.15.3.tgz", + "integrity": "sha512-a1KM5heqS3gQCZzizXEI8RjJy3QVogULPdeSknt76uLDpBIW/HDGsMg/XgP0riP6PI9COsRvFITKKGDqA8fJxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "dmg-builder": "26.15.3", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.15.3.tgz", + "integrity": "sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "electron-winstaller": "5.4.0" + } + }, + "node_modules/electron-publish": { + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.15.3.tgz", + "integrity": "sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "aws4": "^1.13.2", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", + "chalk": "^4.1.2", + "form-data": "^4.0.5", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-updater": { + "version": "6.8.9", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.9.tgz", + "integrity": "sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==", + "license": "MIT", + "dependencies": { + "builder-util-runtime": "9.7.0", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "~7.7.3", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron-winstaller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-winstaller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.35.0.tgz", + "integrity": "sha512-ymk4aIzxdPopw2giv8Fs1Ec6vybGkjmyxUwVqhkI4MCy2tVfXdkOGGWieWVjL0THgH+7a8lRdevyupoYj3Js/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-gyp": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz", + "integrity": "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "undici": "^6.25.0", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-gyp/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-gyp/node_modules/undici": { + "version": "6.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz", + "integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkijs": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.1.tgz", + "integrity": "sha512-Oo/NZcSWccq8KyoG7gLE9fnltgHns+pNCjCAp/WmjsUySi+sX7y4z4Xqu4fVb42CDHzRPl33fjzT15V1wvcyhA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "website" + ], + "dependencies": { + "@noble/hashes": "1.8.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/pkijs/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/playwright": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", + "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici": { + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.0.tgz", + "integrity": "sha512-dkrQXeHSaoamnItlYbmzG0wFYrM0ZwDxCIg0A7aKjTyyhh9svRzCNFEzV+Vm05/yehjCzjDZ31KXfGEjYSztDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unzipper": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", + "integrity": "sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "11.3.1", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" + } + }, + "node_modules/unzipper/node_modules/fs-extra": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/webcrypto-core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.9.2.tgz", + "integrity": "sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/json-schema": "^1.1.12", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/desktop/package.json b/desktop/package.json new file mode 100644 index 0000000..c7a1383 --- /dev/null +++ b/desktop/package.json @@ -0,0 +1,104 @@ +{ + "name": "rieke-os-desktop", + "version": "0.1.3", + "private": true, + "description": "Rieke OS self-contained desktop application", + "author": "Rieke OS contributors", + "main": "main.cjs", + "scripts": { + "start": "electron .", + "test": "node --test tests/*.test.cjs test/*.test.cjs", + "test:e2e": "node e2e/packaged.e2e.cjs", + "test:e2e:startup-failure": "node e2e/backend-failure.e2e.cjs", + "test:e2e:updater": "electron tests/e2e/updater-client.cjs", + "pack": "electron-builder --mac --arm64 --dir", + "dist": "electron-builder --mac dmg zip --arm64 --publish never", + "test:e2e:bootstrap": "node e2e/bootstrap.e2e.cjs", + "test:e2e:github-updates": "node e2e/github-updates.e2e.cjs" + }, + "dependencies": { + "electron-updater": "6.8.9" + }, + "devDependencies": { + "electron": "44.5.0", + "electron-builder": "26.15.3", + "playwright": "1.63.0" + }, + "build": { + "appId": "org.riekeos.desktop", + "productName": "Rieke OS", + "artifactName": "Rieke-OS-${version}-${arch}.${ext}", + "asar": true, + "directories": { + "output": "dist", + "buildResources": "assets" + }, + "files": [ + "*.cjs", + "*.html", + "*.css", + "recovery.js", + "icon.png", + "package.json", + "distribution.json" + ], + "extraResources": [ + { + "from": "build/runtime", + "to": "runtime", + "filter": [ + "**/*" + ] + } + ], + "mac": { + "target": [ + { + "target": "dmg", + "arch": [ + "arm64" + ] + }, + { + "target": "zip", + "arch": [ + "arm64" + ] + } + ], + "category": "public.app-category.education", + "icon": "icon.png", + "minimumSystemVersion": "14.0", + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "entitlements.mac.plist", + "entitlementsInherit": "entitlements.mac.plist", + "notarize": true, + "sign": "./sign-runtime.cjs" + }, + "dmg": { + "sign": false, + "title": "Open Rieke OS to install", + "backgroundColor": "#f7f4fa", + "window": { + "width": 560, + "height": 400 + }, + "contents": [ + { + "x": 280, + "y": 180, + "type": "file", + "name": "Rieke OS.app" + } + ] + }, + "publish": { + "provider": "github", + "owner": "maxwellsdm1867", + "repo": "Rieke-OS", + "releaseType": "draft" + }, + "afterPack": "./seal-testing.cjs" + } +} diff --git a/desktop/physical-fs.cjs b/desktop/physical-fs.cjs new file mode 100644 index 0000000..9f541a9 --- /dev/null +++ b/desktop/physical-fs.cjs @@ -0,0 +1,5 @@ +'use strict'; +// Bundle validation and replacement operate on physical files. Electron's +// ordinary fs presents an ASAR archive as a virtual directory for module loads. +// Node-based tooling uses the same physical filesystem API without Electron. +module.exports = process.versions.electron ? require('original-fs') : require('node:fs'); diff --git a/desktop/preload.cjs b/desktop/preload.cjs new file mode 100644 index 0000000..5676ddb --- /dev/null +++ b/desktop/preload.cjs @@ -0,0 +1,27 @@ +'use strict'; +const {contextBridge, ipcRenderer} = require('electron'); +function subscribe(channel, callback) { + if (typeof callback !== 'function') throw new TypeError('Callback required'); + const listener = (_event, value) => callback(value); + ipcRenderer.on(channel, listener); + return () => ipcRenderer.removeListener(channel, listener); +} +contextBridge.exposeInMainWorld('riekeDesktop', Object.freeze({ + protocolVersion: 1, + status: () => ipcRenderer.invoke('desktop:status'), + checkForUpdates: () => ipcRenderer.invoke('desktop:check-updates'), + downloadUpdate: () => ipcRenderer.invoke('desktop:download-update'), + restartToUpdate: () => ipcRenderer.invoke('desktop:restart-to-update'), + onStatus: callback => subscribe('desktop:status-changed', callback), + onPrepareClose: callback => subscribe('desktop:prepare-close', callback), + acknowledgeDrafts: (requestId, result) => ipcRenderer.invoke('desktop:drafts-ack', {requestId, ok: result?.ok === true}), + chooseProjectFolder: () => ipcRenderer.invoke('desktop:choose-project-folder'), + saveDraft: payload => ipcRenderer.invoke('desktop:save-draft', payload), + loadDraft: projectId => ipcRenderer.invoke('desktop:load-draft', projectId), + resetDraft: projectId => ipcRenderer.invoke('desktop:reset-draft', projectId), + openReleaseNotes: url => ipcRenderer.invoke('desktop:open-release-notes', url), + installAndOpen: () => ipcRenderer.invoke('desktop:install-and-open'), + retryStartup: () => ipcRenderer.invoke('desktop:retry-startup'), + restorePreviousVersion: () => ipcRenderer.invoke('desktop:restore-previous'), + quit: () => ipcRenderer.invoke('desktop:quit') +})); diff --git a/desktop/python-runtime.json b/desktop/python-runtime.json new file mode 100644 index 0000000..c46d7da --- /dev/null +++ b/desktop/python-runtime.json @@ -0,0 +1,10 @@ +{ + "format": "rieke-standalone-python", + "version": 1, + "python_version": "3.11.13", + "build": "20251007", + "platform": "darwin", + "architecture": "arm64", + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20251007/cpython-3.11.13%2B20251007-aarch64-apple-darwin-install_only_stripped.tar.gz", + "sha256": "78bc6defdc1dac5bf6765c8f938e6849383dbed831ea1e2d11576a4683fb1e8c" +} diff --git a/desktop/recovery-install.cjs b/desktop/recovery-install.cjs new file mode 100644 index 0000000..d3be0ef --- /dev/null +++ b/desktop/recovery-install.cjs @@ -0,0 +1,29 @@ +'use strict'; +// Dedicated, app-owned recovery entry point. The parent has already drained all +// services; this helper additionally waits for the main process to actually exit. +const path = require('node:path'); +const os = require('node:os'); +const fs = require('./physical-fs.cjs').promises; +const {promisify} = require('node:util'); +const run = promisify(require('node:child_process').execFile); +const {installCompleteBundle, signatureIdentity, readBundleManifest, enclosingApp} = require('./bootstrap.cjs'); +async function main() { + const [pidText, previous, destination] = process.argv.slice(2); + const pid = Number(pidText); + const expected = path.join(os.homedir(), 'Applications', 'Rieke OS.app'); + if (!Number.isSafeInteger(pid) || pid <= 0 || destination !== expected || enclosingApp(process.execPath) !== destination || !previous.endsWith(path.join('updates', 'previous', 'Rieke OS.app'))) throw new Error('Invalid recovery request.'); + const current = await signatureIdentity(destination), prior = await signatureIdentity(previous); + if (current.team !== prior.team) throw new Error('Recovery signature differs.'); + const deadline = Date.now() + 60000; + for (;;) { + let alive = true; + try { process.kill(pid, 0); } catch (error) { if (error.code === 'ESRCH') alive = false; else throw error; } + if (!alive) break; + if (Date.now() >= deadline) throw new Error('App exit was not acknowledged; recovery deferred.'); + await new Promise(resolve => setTimeout(resolve, 200)); + } + await installCompleteBundle({source: previous, destination, allowRollback: true, ignorePid: process.pid}); + await run('/usr/bin/open', ['-n', destination]); +} +if (require.main === module) main().catch(() => { process.exitCode = 1; }); +module.exports = {main}; diff --git a/desktop/recovery.css b/desktop/recovery.css new file mode 100644 index 0000000..4f0ba5d --- /dev/null +++ b/desktop/recovery.css @@ -0,0 +1 @@ +:root{font-family:-apple-system,BlinkMacSystemFont,sans-serif;color:#202d32;background:#f4f5f3}body{margin:0;display:grid;place-items:center;min-height:100vh}main{width:min(520px,80vw);padding:48px;background:white;border-radius:18px;box-shadow:0 14px 55px #17363a14}h1{font-size:26px;font-weight:600}p{line-height:1.55;color:#566567}#channel{font-size:13px;font-weight:600;color:#72508a}#detail,#gatekeeper{font-size:13px;white-space:pre-wrap}button{font:inherit;border:1px solid #bdcccb;border-radius:7px;padding:10px 16px;margin:10px 8px 0 0;background:#f6f8f7;cursor:pointer}#install{background:#186f69;color:white;border-color:#186f69}button:disabled{opacity:.55;cursor:wait} diff --git a/desktop/recovery.html b/desktop/recovery.html new file mode 100644 index 0000000..1ea6940 --- /dev/null +++ b/desktop/recovery.html @@ -0,0 +1 @@ +Rieke OS

Starting Rieke OS

Verifying the complete app and its private runtime.

diff --git a/desktop/recovery.js b/desktop/recovery.js new file mode 100644 index 0000000..30f85cc --- /dev/null +++ b/desktop/recovery.js @@ -0,0 +1,23 @@ +'use strict'; +const bridge = window.riekeDesktop; +function display(status) { + const testing = status.channel === 'unsigned-testing'; + document.getElementById('title').textContent = status.title || 'Rieke OS recovery'; + document.getElementById('message').textContent = status.message || 'Startup has not completed.'; + document.getElementById('detail').textContent = status.detail || ''; + document.getElementById('channel').textContent = 'Unsigned testing'; + document.getElementById('channel').hidden = !testing; + document.getElementById('gatekeeper').textContent = 'If macOS blocks this unsigned testing app on its first open, choose Open Anyway in System Settings → Privacy & Security.'; + document.getElementById('gatekeeper').hidden = !testing || status.state !== 'Bootstrap' || (status.detail || '').includes('Open Anyway'); + document.getElementById('install').hidden = status.state !== 'Bootstrap'; + document.getElementById('retry').hidden = status.state !== 'Recovery'; + document.getElementById('restore').hidden = status.state !== 'Recovery'; +} +bridge.status().then(display); bridge.onStatus(display); +for (const [id, action] of [['install', () => bridge.installAndOpen()], ['retry', () => bridge.retryStartup()], ['restore', () => bridge.restorePreviousVersion()], ['quit', () => bridge.quit()]]) { + document.getElementById(id).onclick = async event => { + event.target.disabled = true; + try { const result = await action(); if (result?.ready === false) document.getElementById('detail').textContent = result.reason || 'The app is waiting for current work to finish.'; } catch (error) { document.getElementById('detail').textContent = error.message; } + finally { event.target.disabled = false; } + }; +} diff --git a/desktop/requirements.lock b/desktop/requirements.lock new file mode 100644 index 0000000..30617d4 --- /dev/null +++ b/desktop/requirements.lock @@ -0,0 +1,3 @@ +# Production WSGI service; install alongside python/workspace-runtime.lock. +waitress==3.0.2 \ + --hash=sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e diff --git a/desktop/seal-testing.cjs b/desktop/seal-testing.cjs new file mode 100644 index 0000000..2d0b471 --- /dev/null +++ b/desktop/seal-testing.cjs @@ -0,0 +1,19 @@ +'use strict'; +// A local ad-hoc seal makes the complete bundle structurally valid. It provides +// no Developer ID identity, notarization, or Gatekeeper approval. +const path=require('node:path'); +const {execFile}=require('node:child_process'); +const {promisify}=require('node:util'); +const {distributionPolicy}=require('./distribution.cjs'); +module.exports=async context=>{ + const distribution=distributionPolicy(require('./distribution.json')); + if(distribution.channel!=='unsigned-testing'||context.electronPlatformName!=='darwin')return; + const app=path.join(context.appOutDir,`${context.packager.appInfo.productFilename}.app`); + const runtime=path.join(app,'Contents/Resources/runtime'); + const {signAsync}=require('@electron/osx-sign'); + await signAsync({app,identity:'-',identityValidation:false,platform:'darwin',type:'development', + preAutoEntitlements:false,preEmbedProvisioningProfile:false,gatekeeperAssess:false, + optionsForFile:()=>({hardenedRuntime:false,timestamp:'none',entitlements:path.join(__dirname,'entitlements.mac.plist')}), + ignore:filename=>filename===runtime||filename.startsWith(runtime+path.sep)}); + await promisify(execFile)('/usr/bin/codesign',['--verify','--deep','--strict',app]); +}; diff --git a/desktop/security.cjs b/desktop/security.cjs new file mode 100644 index 0000000..55dce93 --- /dev/null +++ b/desktop/security.cjs @@ -0,0 +1,34 @@ +'use strict'; +const path = require('node:path'); +const {fileURLToPath} = require('node:url'); +const PROJECT_ID = /^(?:launcher|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i; +function isOwnedURL(url, origin, localPages = []) { + try { + const parsed = new URL(url); + if (parsed.username || parsed.password) return false; + if (origin && (typeof origin === 'string' ? parsed.origin === origin : origin.has(parsed.origin)) && parsed.protocol === 'http:') return true; + return parsed.protocol === 'file:' && localPages.includes(path.resolve(fileURLToPath(parsed))); + } catch { return false; } +} +function validateSender(event, windows, origin, localPages) { + const window = [...windows].find(win => !win.isDestroyed() && win.webContents === event.sender); + if (!window || !event.senderFrame || event.senderFrame !== event.sender.mainFrame || + !isOwnedURL(event.senderFrame.url, origin, localPages)) throw new Error('Unauthorized desktop frame'); + return window; +} +function validateProjectId(value) { + if (typeof value !== 'string' || !PROJECT_ID.test(value)) throw new TypeError('Invalid project identity'); + return value.toLowerCase(); +} +function validateDraft(payload) { + if (!payload || Object.keys(payload).sort().join(',') !== 'projectId,value') throw new TypeError('Invalid draft payload'); + const projectId = validateProjectId(payload.projectId); + const serialized = JSON.stringify(payload.value); + if (serialized === undefined || Buffer.byteLength(serialized) > 2 * 1024 * 1024) throw new TypeError('Draft exceeds size limit'); + return {projectId, serialized}; +} +function approvedReleaseURL(value) { + try { const url = new URL(value); return url.protocol === 'https:' && url.hostname === 'github.com' && + !url.username && !url.password && /^\/maxwellsdm1867\/Rieke-OS\/releases(?:\/|$)/.test(url.pathname); } catch { return false; } +} +module.exports = {isOwnedURL, validateSender, validateDraft, validateProjectId, approvedReleaseURL}; diff --git a/desktop/sign-runtime.cjs b/desktop/sign-runtime.cjs new file mode 100644 index 0000000..eb2b039 --- /dev/null +++ b/desktop/sign-runtime.cjs @@ -0,0 +1,64 @@ +'use strict'; +// Pinned electron-builder 26.15.3 mac.sign(opts, packager) hook. Finish native +// signing first; hash final runtime bytes; then seal the outer application once. +const fs = require('node:fs/promises'); +const {createReadStream} = require('node:fs'); +const path = require('node:path'); +const {createHash} = require('node:crypto'); +const {execFile} = require('node:child_process'); +const {promisify} = require('node:util'); +const run = promisify(execFile); +const MACH_O = new Set([0xfeedface, 0xfeedfacf, 0xcefaedfe, 0xcffaedfe, 0xcafebabe, 0xbebafeca, 0xcafebabf, 0xbfbafeca]); +async function sha256(filename) { + const digest = createHash('sha256'); + for await (const chunk of createReadStream(filename)) digest.update(chunk); + return digest.digest('hex'); +} +async function inventory(root) { + const entries = []; + async function visit(directory) { + for (const entry of await fs.readdir(directory, {withFileTypes: true})) { + const absolute = path.join(directory, entry.name); + if (entry.isDirectory()) await visit(absolute); + else entries.push({absolute, relative: path.relative(root, absolute).split(path.sep).join('/'), symbolic: entry.isSymbolicLink()}); + } + } + await visit(root); return entries.sort((a, b) => a.relative.localeCompare(b.relative)); +} +async function resealRuntimeManifest(root) { + const manifestPath = path.join(root, 'runtime-manifest.json'); + const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')); + const resources = {}; + for (const item of await inventory(root)) { + if (['runtime-manifest.json', 'runtime-audit.json'].includes(item.relative)) continue; + if (item.symbolic) resources[item.relative] = {symlink: await fs.readlink(item.absolute)}; + else { const stat = await fs.stat(item.absolute); resources[item.relative] = {sha256: await sha256(item.absolute), size: stat.size, executable: Boolean(stat.mode & 0o111)}; } + } + manifest.resources = resources; + await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n'); + return manifest; +} +async function signRuntime(options) { + if (!options.identity || options.identity === '-') throw new Error('Production runtime signing requires a Developer ID identity'); + const runtime = path.join(options.app, 'Contents', 'Resources', 'runtime'); + // No signature mutation may follow this inventory seal. + for (const item of await inventory(runtime)) { + if (item.symbolic) continue; + const handle = await fs.open(item.absolute, 'r'); + const magic = Buffer.alloc(4); let bytesRead; + try { ({bytesRead} = await handle.read(magic, 0, 4, 0)); } finally { await handle.close(); } + if (bytesRead !== 4 || !MACH_O.has(magic.readUInt32BE())) continue; + const args = ['--force', '--sign', options.identity, '--timestamp', '--options', 'runtime']; + if (options.keychain) args.push('--keychain', options.keychain); + if (item.relative === 'python/bin/python3.11') args.push('--entitlements', path.join(__dirname, 'entitlements.mac.plist')); + args.push(item.absolute); await run('/usr/bin/codesign', args); + } + await resealRuntimeManifest(runtime); + const {signAsync} = require('@electron/osx-sign'); + const previousIgnore = options.ignore == null ? [] : Array.isArray(options.ignore) ? options.ignore : [options.ignore]; + await signAsync({...options, ignore: [...previousIgnore, filename => filename === runtime || filename.startsWith(runtime + path.sep)]}); + await run('/usr/bin/codesign', ['--verify', '--deep', '--strict', options.app]); +} +module.exports = signRuntime; +module.exports.resealRuntimeManifest = resealRuntimeManifest; +module.exports.inventory = inventory; diff --git a/desktop/supervisor.cjs b/desktop/supervisor.cjs new file mode 100644 index 0000000..9062909 --- /dev/null +++ b/desktop/supervisor.cjs @@ -0,0 +1,178 @@ +'use strict'; +const fs = require('node:fs/promises'); +const path = require('node:path'); +const net = require('node:net'); +const {spawn, execFile} = require('node:child_process'); +const {promisify} = require('node:util'); +const {randomUUID, randomBytes, createHash} = require('node:crypto'); +const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); +async function inspectExecutable(pid) { + try { + const {stdout} = await promisify(execFile)('/bin/ps', ['-p', String(pid), '-o', 'comm=']); + const executable = stdout.trim(); return executable ? await fs.realpath(executable) : null; + } catch (error) { if (error.code === 1 || error.code === 'ENOENT') return null; throw error; } +} +async function atomicJSON(filename, value) { + await fs.mkdir(path.dirname(filename), {recursive: true, mode: 0o700}); + const temporary = `${filename}.${randomUUID()}.tmp`; + await fs.writeFile(temporary, JSON.stringify(value, null, 2), {mode: 0o600}); + await fs.rename(temporary, filename); +} +async function availablePort() { + const server = net.createServer(); + await new Promise((resolve, reject) => server.once('error', reject).listen(0, '127.0.0.1', resolve)); + const port = server.address().port; + await new Promise(resolve => server.close(resolve)); + return port; +} +function matchesHealth(health, expected) { + return health?.ready === true && Object.entries(expected).every(([key, value]) => + JSON.stringify(health[key]) === JSON.stringify(value)); +} +class ServiceSupervisor { + constructor({resourcesPath, userData, appVersion, spawnProcess = spawn, request = fetch, inspectProcess = inspectExecutable, startupTimeout = 90000, drainTimeout = 30000, onFailure = () => {}}) { + Object.assign(this, {resourcesPath, userData, appVersion, spawnProcess, request, inspectProcess, startupTimeout, drainTimeout, onFailure}); + this.capability = randomBytes(32).toString('hex'); this.sessionId = randomUUID(); + this.rendererCapability = createHash('sha256').update(this.capability + ':renderer').digest('hex'); + this.origins = new Set(); this.child = null; this.exited = true; this.ready = false; + this.registryPath = path.join(userData, 'desktop-service.json'); + } + async loadManifest() { + const runtime = path.join(this.resourcesPath, 'runtime'); + const manifestPath = path.join(runtime, 'runtime-manifest.json'); + this.manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')); + if (this.manifest.format !== 'rieke-desktop-runtime' || this.manifest.version !== 1 || + this.manifest.platform !== process.platform || this.manifest.architecture !== process.arch || + this.manifest.application_version !== this.appVersion || !this.manifest.source_commit || + !Array.isArray(this.manifest.workspace_formats) || !Number.isInteger(this.manifest.database_compatibility)) + throw new Error('Packaged runtime identity or compatibility does not match this application'); + this.executable = await fs.realpath(path.join(runtime, 'python', 'bin', 'python3.11')); + this.entry = await fs.realpath(path.join(runtime, 'application', 'python', 'workspace_desktop.py')); + const root = await fs.realpath(runtime); + if (![this.executable, this.entry].every(item => item.startsWith(root + path.sep))) throw new Error('Runtime entry escapes packaged resources'); + return this.manifest; + } + async start() { + if (this.child && !this.exited) throw new Error('Previous backend is still running; replacement is deferred'); + await this.loadManifest(); + try { + const previous = JSON.parse(await fs.readFile(this.registryPath, 'utf8')); + if (!Number.isSafeInteger(previous.pid) || previous.pid <= 0 || !path.isAbsolute(previous.executable || '') || !previous.session_id) + throw new Error('Previous service registry is malformed; resolve recovery before opening projects'); + const actualExecutable = await this.inspectProcess(previous.pid); + if (actualExecutable === previous.executable) throw new Error('A prior matching service is still active; resolve recovery before opening projects'); + for (const record of previous.services || []) { + if (await this.inspectProcess(record.pid) === previous.executable) + throw new Error('A prior project service is still active; resolve recovery before opening projects'); + } + // PID reuse is never treated as ownership and never authorizes termination. + } catch (error) { if (error.code !== 'ENOENT') throw error; } + const port = await availablePort(); this.origin = `http://127.0.0.1:${port}`; + const backendState = path.join(this.userData, 'backend'); + await fs.mkdir(backendState, {recursive: true, mode: 0o700}); + const env = {HOME: process.env.HOME, TMPDIR: process.env.TMPDIR, LANG: 'en_US.UTF-8', + PYTHONDONTWRITEBYTECODE: '1', PYTHONNOUSERSITE: '1', RIEKE_DESKTOP_CAPABILITY: this.capability, + RIEKE_PARSER_CONFIG: path.join(backendState, 'parser', 'config.ini')}; + this.child = this.spawnProcess(this.executable, ['-B', this.entry, '--host', '127.0.0.1', '--port', String(port), + '--resources', this.resourcesPath, '--user-state', backendState, + '--manifest', path.join(this.resourcesPath, 'runtime', 'runtime-manifest.json'), '--session-id', this.sessionId], + {cwd: backendState, env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true}); + this.exited = false; this.exitCode = null; this.abnormalExit = false; this.stopping = false; this.bound = false; + const expectedBound = {pid: this.child.pid, session_id: this.sessionId, port, + application_version: this.appVersion, source_commit: this.manifest.source_commit}; + let finishBound; + const binding = new Promise(resolve => { finishBound = resolve; }); + let stdoutPending = ''; + this.child.stdout?.on('data', chunk => { + stdoutPending += chunk.toString('utf8'); + if (stdoutPending.length > 65536) { stdoutPending = ''; return; } + let index; + while ((index = stdoutPending.indexOf('\n')) >= 0) { + const line = stdoutPending.slice(0, index); stdoutPending = stdoutPending.slice(index + 1); + if (!line.startsWith('RIEKE_DESKTOP_BOUND=')) continue; + try { + const value = JSON.parse(line.slice('RIEKE_DESKTOP_BOUND='.length)); + if (Object.entries(expectedBound).every(([key, expected]) => value[key] === expected)) { + this.bound = true; finishBound(true); + } + } catch {} + } + }); + this.child.once('error', () => { this.exited = true; this.exitCode = 'spawn'; finishBound(false); }); + this.child.once('exit', code => { this.exited = true; this.exitCode = code; this.abnormalExit = !this.stopping; + finishBound(false); if (this.ready && !this.stopping) { this.origins.clear(); this.onFailure('The owned backend stopped unexpectedly. Scientific projects are closed until recovery.'); } }); + // Backend output may contain scientific paths or credentials. Do not persist or expose it. + this.child.stdout?.resume(); this.child.stderr?.resume(); + this.registry = {pid: this.child.pid, executable: this.executable, entry: this.entry, + session_id: this.sessionId, source_commit: this.manifest.source_commit, application_version: this.appVersion, port}; + await atomicJSON(this.registryPath, this.registry); + const expected = this.expectedHealth(); const deadline = Date.now() + this.startupTimeout; + let boundTimer; + const bound = await Promise.race([binding, new Promise(resolve => { boundTimer = setTimeout(() => resolve(false), this.startupTimeout); })]); + clearTimeout(boundTimer); + if (!bound) throw new Error(this.exited ? `Packaged backend exited before owning its listener (${this.exitCode})` : 'Packaged backend listener deadline exceeded; no desktop capability was sent'); + while (Date.now() < deadline && !this.exited) { + try { + const health = await this.api('/api/desktop/health'); + if (!matchesHealth(health, expected)) throw new Error('Owned backend identity mismatch'); + this.origins.add(this.origin); this.ready = true; return this.origin; + } catch (error) { this.lastStartupError = error.message; await delay(200); } + } + throw new Error(this.exited ? `Packaged backend exited before readiness (${this.exitCode})` : 'Packaged backend readiness deadline exceeded; backend retained for safe recovery'); + } + expectedHealth() { return {pid: this.child.pid, session_id: this.sessionId, + application_version: this.manifest.application_version, source_commit: this.manifest.source_commit, + workspace_formats: this.manifest.workspace_formats, database_compatibility: this.manifest.database_compatibility}; } + async api(route, {origin = this.origin, method = 'GET', timeout = 3000, body = {}} = {}) { + if (!this.bound) throw new Error('Owned backend has not proved listener ownership'); + if (origin !== this.origin || !/^\/api\/desktop\/[a-z-]+$/.test(route)) throw new Error('Desktop controls target only the exact owned root service'); + const response = await this.request(`${origin}${route}`, {method, + headers: {'X-Rieke-Desktop-Capability': this.capability, 'X-Workspace-Request': '1', 'Content-Type': 'application/json'}, + signal: AbortSignal.timeout(timeout), ...(method === 'POST' ? {body: JSON.stringify(body)} : {})}); + let value; try { value = await response.json(); } catch { throw new Error('Malformed desktop service response'); } + if (!response.ok) throw new Error(value.error || (response.status === 409 ? 'Scientific writes are still active' : 'Desktop service request failed')); + return value; + } + async authorizeProjectURL(value) { + const url = new URL(value); + if (url.protocol !== 'http:' || url.hostname !== '127.0.0.1' || url.username || url.password) return false; + const rootHealth = await this.api('/api/desktop/health'); + if (!matchesHealth(rootHealth, this.expectedHealth())) return false; + if (url.origin === this.origin) return true; + this.registry.services = rootHealth.services || []; + await atomicJSON(this.registryPath, this.registry); + const record = rootHealth.services?.find(item => item.port === Number(url.port)); + if (!record || record.bound !== true || record.session_id !== this.sessionId || !record.project_uuid || !record.project_path) { this.origins.delete(url.origin); return false; } + // Root owns the child's private bind receipt and exact process creation time. + // It performs the native process check before sending control capabilities; + // main never sends its capability to a possibly reused child port. + const authorization = await this.api('/api/desktop/authorize-project', {method: 'POST', body: {port: Number(url.port)}}); + if (!authorization.record || !Object.entries(record).every(([key, value]) => JSON.stringify(authorization.record[key]) === JSON.stringify(value))) return false; + const childHealth = authorization.health; + if (!matchesHealth(childHealth, {pid: record.pid, session_id: this.sessionId, + application_version: this.appVersion, source_commit: this.manifest.source_commit, + workspace_formats: this.manifest.workspace_formats, database_compatibility: this.manifest.database_compatibility, + project_uuid: record.project_uuid, project_path: record.project_path})) return false; + this.origins.add(url.origin); return true; + } + async drain() { + if (this.abnormalExit) return {ready: false, reason: 'Backend exited without a drain acknowledgement; project service exit must be recovered before replacement'}; + if (!this.child || this.exited) { this.ready = false; await fs.rm(this.registryPath, {force: true}); return {ready: true}; } + try { + const result = await this.api('/api/desktop/drain', {method: 'POST', timeout: this.drainTimeout}); + if (result.ready !== true) throw new Error('Backend did not acknowledge drain'); + // Ack only starts the exit phase; process exit is independent required evidence. + this.stopping = true; + await this.api('/api/desktop/stop', {method: 'POST', timeout: 3000}); + const deadline = Date.now() + this.drainTimeout; this.ready = false; + while (!this.exited && Date.now() < deadline) await delay(50); + if (!this.exited) return {ready: false, reason: 'Backend has not acknowledged process exit; replacement is deferred'}; + this.origins.clear(); await fs.rm(this.registryPath, {force: true}); return {ready: true}; + } catch (error) { + this.stopping = false; + try { await this.api('/api/desktop/resume', {method: 'POST'}); } catch {} + return {ready: false, reason: error.message}; + } + } +} +module.exports = {ServiceSupervisor, matchesHealth, atomicJSON, availablePort, inspectExecutable}; diff --git a/desktop/test/testing-updater.test.cjs b/desktop/test/testing-updater.test.cjs new file mode 100644 index 0000000..e5c8c39 --- /dev/null +++ b/desktop/test/testing-updater.test.cjs @@ -0,0 +1,216 @@ +'use strict'; +const test=require('node:test'),assert=require('node:assert/strict'); +const fs=require('node:fs/promises'),path=require('node:path'),os=require('node:os'),crypto=require('node:crypto'),http=require('node:http'); +const {Readable}=require('node:stream'); +const {validateDescriptor,approvedURL,inspectTestingBundle,validateTestingCandidate,revalidateTestingCandidate}=require('../testing-update-validation.cjs'); +const {createTestingUpdateCoordinator}=require('../testing-updater.cjs'); +const current={application_version:'0.1.2',platform:'darwin',architecture:'arm64',mysql_version:'8.4.2',database_compatibility:1,workspace_formats:[1]}; +const bytes=Buffer.from('candidate archive bytes'); +const descriptor={format:'rieke-desktop-test-release',version:1,channel:'unsigned-testing',repository:'maxwellsdm1867/Rieke-OS',application_version:'0.1.3',platform:'darwin',architecture:'arm64',mysql_version:'8.4.2',database_compatibility:1,workspace_formats:[1],minimum_macos_version:'14.0',archive:{filename:'Rieke-OS-0.1.3-arm64.zip',size:bytes.length,sha256:crypto.createHash('sha256').update(bytes).digest('hex'),sha512:crypto.createHash('sha512').update(bytes).digest('base64')},asar_sha256:'a'.repeat(64),runtime_manifest_sha256:'b'.repeat(64)}; +const distribution={format:'rieke-desktop-distribution',version:1,channel:'unsigned-testing',repository:'maxwellsdm1867/Rieke-OS'}; +const base='https://github.com/maxwellsdm1867/Rieke-OS/releases/download/desktop-test-v0.1.3/'; +test('testing descriptor and URL boundaries reject foreign provenance, migration and nonstable versions',()=>{ + assert.equal(validateDescriptor(descriptor,current,'14.2'),descriptor); + for(const patch of [{channel:'signed'},{repository:'foreign/repo'},{application_version:'0.1.2'},{application_version:'0.1.3-beta'},{architecture:'x64'},{database_compatibility:2},{workspace_formats:[2]},{minimum_macos_version:'15.0'},{archive:{...descriptor.archive,filename:'../bad.zip'}},{archive:{...descriptor.archive,size:0}},{archive:{...descriptor.archive,sha512:'bad'}}])assert.throws(()=>validateDescriptor({...descriptor,...patch},current,'14.2')); + assert.equal(approvedURL(base+descriptor.archive.filename,'asset'),true); + for(const url of ['http://github.com/maxwellsdm1867/Rieke-OS/releases/download/v0.1.3/a.zip','https://github.com/foreign/repo/releases/download/v1/a.zip','https://github.com.evil.invalid/maxwellsdm1867/Rieke-OS/releases/download/v1/a.zip','https://user:secret@github.com/maxwellsdm1867/Rieke-OS/releases/download/v1/a.zip','https://api.github.com/repos/foreign/repo/releases','https://127.0.0.1/releases'])assert.throws(()=>approvedURL(url,'asset')); +}); +async function fixture(t,options={}){ + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-testing-update-')); + const release={draft:false,prerelease:true,tag_name:'desktop-test-v0.1.3',html_url:'https://github.com/maxwellsdm1867/Rieke-OS/releases/tag/desktop-test-v0.1.3',assets:[{name:'desktop-release.json',size:1000,browser_download_url:base+'desktop-release.json'},{name:descriptor.archive.filename,size:bytes.length,browser_download_url:base+descriptor.archive.filename}]}; + let archiveCalls=0,helperCalls=0,drains=0,validationCalls=0,failDownload=false,failMetadata=false,metadataCalls=0; + let archiveBytes=bytes; + const server=http.createServer((request,response)=>{ + const url=new URL(request.url,'http://fixture'); + if(url.pathname.endsWith('/releases')){metadataCalls++;if(failMetadata){response.writeHead(503);response.end('offline');}else response.end(JSON.stringify([release]));} + else if(url.pathname.endsWith('/desktop-release.json'))response.end(JSON.stringify(descriptor)); + else {archiveCalls++;if(failDownload){response.writeHead(200,{'Content-Length':bytes.length+10});response.end(bytes.subarray(0,2));}else response.end(archiveBytes);} + }); + await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve)); + const transport=url=>new Promise((resolve,reject)=>{ + const official=new URL(url); + http.get({hostname:'127.0.0.1',port:server.address().port,path:official.pathname+official.search},response=>resolve({statusCode:response.statusCode,headers:response.headers,body:response})).on('error',reject); + }); + const app={isPackaged:true,getPath:name=>name==='exe'?path.join(root,'Installed.app/Contents/MacOS/Rieke OS'):root}; + await fs.mkdir(path.join(root,'Installed.app/Contents/Resources/runtime'),{recursive:true}); + await fs.writeFile(path.join(root,'Installed.app/Contents/Resources/runtime/runtime-manifest.json'),JSON.stringify(current)); + const coordinator=createTestingUpdateCoordinator({app,manifest:current,distribution,transport,hostVersion:'14.2', + timers:{setTimeout:()=>({unref(){}}),clearTimeout(){}}, + verifyCandidate:async args=>{validationCalls++;const directory=await fs.mkdtemp(path.join(args.cacheDirectory,'candidate-'));const bundle=path.join(directory,'Rieke OS.app');await fs.mkdir(bundle);return {version:args.descriptor.application_version,downloadedFile:args.downloadedFile,bundle_path:bundle,candidate_directory:directory,bundle_sha256:'c'.repeat(64),archive_sha256:descriptor.archive.sha256,runtime_manifest_sha256:descriptor.runtime_manifest_sha256,validated:true};}, + revalidateCandidate:async()=>{}, + prepareQuit:async()=>{drains++;return{ready:true};}, + processIdentity:async()=> 'fixture-process-start', + installHelper:async()=>{helperCalls++;},...options}); + t.after(async()=>{coordinator.stop();await coordinator.flushReceipts();await new Promise(resolve=>server.close(resolve));await fs.rm(root,{recursive:true,force:true});}); + return{root,app,transport,coordinator,archiveCalls:()=>archiveCalls,helperCalls:()=>helperCalls,drains:()=>drains,validationCalls:()=>validationCalls,metadataCalls:()=>metadataCalls,setMetadataFailure:()=>{failMetadata=true;},setDownloadFailure:()=>{failDownload=true;},retryDownload:()=>{failDownload=false;},corruptDownload:()=>{archiveBytes=Buffer.from('corrupt');}}; +} +test('startup metadata notice never downloads; explicit download prepares and orderly install runs once',async t=>{ + const f=await fixture(t);await f.coordinator.start(); + assert.equal(f.coordinator.getStatus().state,'Available');assert.equal(f.archiveCalls(),0); + await f.coordinator.download();assert.equal(f.coordinator.getStatus().state,'Ready');assert.equal(f.archiveCalls(),1); + const result=await Promise.all([f.coordinator.installPrepared(),f.coordinator.installPrepared()]); + assert.ok(result.every(r=>r.installing));assert.equal(f.helperCalls(),1);assert.equal(f.drains(),1); +}); +test('truncated and checksum-failed downloads never validate and permit a fresh explicit retry',async t=>{ + const f=await fixture(t);await f.coordinator.start();f.setDownloadFailure(); + await f.coordinator.download();assert.notEqual(f.coordinator.getStatus().state,'Ready');assert.equal(f.validationCalls(),0); + f.retryDownload();await f.coordinator.download();assert.equal(f.coordinator.getStatus().state,'Ready'); + const bad=await fixture(t);await bad.coordinator.start();bad.corruptDownload();await bad.coordinator.download(); + assert.notEqual(bad.coordinator.getStatus().state,'Ready');assert.equal(bad.validationCalls(),0); +}); +test('cached archive corruption during drain revokes install authority',async t=>{ + let target; + const f=await fixture(t,{prepareQuit:async()=>{await fs.appendFile(target,'changed');return{ready:true};}}); + await f.coordinator.start();await f.coordinator.download(); + const directories=await fs.readdir(path.join(f.root,'updates/unsigned-testing')); + const candidate=directories.find(x=>x.startsWith('download-')); + target=path.join(f.root,'updates/unsigned-testing',candidate,descriptor.archive.filename); + assert.equal((await f.coordinator.installPrepared()).ready,false);assert.equal(f.helperCalls(),0); +}); +test('background metadata retry preserves available notice and never consumes the download choice',async t=>{ + let hourly; + const f=await fixture(t,{timers:{setTimeout:callback=>{hourly=callback;return{unref(){}};},clearTimeout(){}}}); + await f.coordinator.start();assert.equal(f.coordinator.getStatus().can_download,true);f.setMetadataFailure(); + await hourly();assert.equal(f.coordinator.getStatus().state,'Available');assert.equal(f.coordinator.getStatus().available,'0.1.3'); + assert.equal(f.coordinator.getStatus().can_download,true);assert.equal(f.archiveCalls(),0); + await f.coordinator.download();assert.equal(f.coordinator.getStatus().state,'Ready');assert.equal(f.coordinator.getStatus().can_restart,true); + const calls=f.metadataCalls();await f.coordinator.check();assert.equal(f.metadataCalls(),calls);assert.equal(f.coordinator.getStatus().state,'Ready'); +}); +test('cache corruption before drain offers retry without shutting down current services',async t=>{ + const f=await fixture(t);await f.coordinator.start();await f.coordinator.download(); + const directory=(await fs.readdir(path.join(f.root,'updates/unsigned-testing'))).find(x=>x.startsWith('download-')); + await fs.appendFile(path.join(f.root,'updates/unsigned-testing',directory,descriptor.archive.filename),'changed'); + assert.equal((await f.coordinator.installPrepared()).ready,false);assert.equal(f.drains(),0);assert.equal(f.helperCalls(),0); + assert.match(f.coordinator.getStatus().message,/Retry the download/);assert.equal(f.coordinator.getStatus().can_download,true); +}); +test('a persisted Ready hint cannot authorize installation after restart or a failed metadata check',async t=>{ + const f=await fixture(t); + const cache=path.join(f.root,'updates/unsigned-testing');await fs.mkdir(cache,{recursive:true}); + await fs.writeFile(path.join(cache,'status.json'),JSON.stringify({format:'rieke-desktop-testing-update-status',version:1,installed:'0.1.2',available:'0.1.3',state:'Ready'})); + f.setMetadataFailure();await f.coordinator.start(); + assert.equal((await f.coordinator.installPrepared()).ready,false);assert.equal(f.helperCalls(),0); + assert.equal(f.coordinator.getStatus().can_download,false);assert.equal(f.coordinator.getStatus().can_restart,false); +}); +test('ordinary quit preserves downloaded choice; cold start requires fresh official metadata and complete revalidation',async t=>{ + const f=await fixture(t);await f.coordinator.start();await f.coordinator.download(); + f.coordinator.stop();await f.coordinator.flushReceipts();assert.equal(f.helperCalls(),0); + let validations=0; + const resumed=createTestingUpdateCoordinator({app:f.app,manifest:current,distribution,transport:f.transport,hostVersion:'14.2', + timers:{setTimeout:()=>({unref(){}}),clearTimeout(){}}, + revalidateCandidate:async({candidate,descriptor:live})=>{validations++;assert.equal(live.archive.sha256,descriptor.archive.sha256);assert.equal(candidate.bundle_sha256,'c'.repeat(64));return{source_dirty:true};}, + prepareQuit:async()=>({ready:false})}); + const metadataBefore=f.metadataCalls();await resumed.start();assert.ok(f.metadataCalls()>metadataBefore); + assert.equal(resumed.getStatus().state,'Ready');assert.equal(resumed.getStatus().source_dirty,true);assert.equal(validations,1); + assert.equal(f.archiveCalls(),1);assert.equal(f.helperCalls(),0); + resumed.stop();await resumed.flushReceipts(); +}); +test('a changed cached archive or linked resume hint offers a fresh download without install authority',async t=>{ + const f=await fixture(t);await f.coordinator.start();await f.coordinator.download();f.coordinator.stop();await f.coordinator.flushReceipts(); + const cache=path.join(f.root,'updates/unsigned-testing'),hint=JSON.parse(await fs.readFile(path.join(cache,'prepared.json'),'utf8')); + await fs.appendFile(path.join(cache,hint.archive_relative_path),'changed'); + let revalidated=0; + const options={app:f.app,manifest:current,distribution,transport:f.transport,hostVersion:'14.2',timers:{setTimeout:()=>1,clearTimeout(){}},revalidateCandidate:async()=>{revalidated++;}}; + const resumed=createTestingUpdateCoordinator(options);await resumed.start();assert.equal(resumed.getStatus().state,'Available');assert.equal(resumed.getStatus().can_download,true); + assert.equal(revalidated,0);assert.equal((await resumed.installPrepared()).ready,false);resumed.stop();await resumed.flushReceipts(); + const unrelated=path.join(f.root,'outside-hint.json');await fs.writeFile(unrelated,JSON.stringify(hint));await fs.symlink(unrelated,path.join(cache,'prepared.json')); + const linked=createTestingUpdateCoordinator(options);await linked.start();assert.equal(linked.getStatus().state,'Available');assert.equal((await linked.installPrepared()).ready,false); + assert.equal(await fs.readFile(unrelated,'utf8'),JSON.stringify(hint));linked.stop();await linked.flushReceipts(); +}); +test('obsolete-cache cleanup removes only old owned generated directories and preserves links/unrelated files',async t=>{ + const f=await fixture(t);await f.coordinator.start(); + const cache=path.join(f.root,'updates/unsigned-testing'),old=new Date(Date.now()-48*3600000); + for(const name of ['download-old000','candidate-old111','unrelated-user-data']){await fs.mkdir(path.join(cache,name));await fs.writeFile(path.join(cache,name,'retained'),'fixture');await fs.utimes(path.join(cache,name),old,old);} + const outside=path.join(f.root,'outside');await fs.mkdir(outside);await fs.writeFile(path.join(outside,'keep'),'safe'); + await fs.symlink(outside,path.join(cache,'candidate-link00')); + await f.coordinator.download();assert.equal(f.coordinator.getStatus().state,'Ready'); + await assert.rejects(fs.access(path.join(cache,'download-old000')));await assert.rejects(fs.access(path.join(cache,'candidate-old111'))); + assert.equal(await fs.readFile(path.join(outside,'keep'),'utf8'),'safe');assert.ok((await fs.lstat(path.join(cache,'candidate-link00'))).isSymbolicLink()); + assert.equal(await fs.readFile(path.join(cache,'unrelated-user-data/retained'),'utf8'),'fixture'); +}); +test('drain deferral preserves candidate; stopping during acknowledged drain prevents handoff',async t=>{ + const blocked=await fixture(t,{prepareQuit:async()=>({ready:false,reason:'writer active'})}); + await blocked.coordinator.start();await blocked.coordinator.download();assert.equal((await blocked.coordinator.installPrepared()).ready,false); + assert.equal(blocked.coordinator.getStatus().state,'Ready');assert.equal(blocked.helperCalls(),0); + let coordinator; + const stopped=await fixture(t,{prepareQuit:async()=>{coordinator.stop();return{ready:true};}});coordinator=stopped.coordinator; + await coordinator.start();await coordinator.download();assert.equal((await coordinator.installPrepared()).ready,false);assert.equal(stopped.helperCalls(),0); +}); +test('symlinked cache root and foreign explicit distribution never gain update authority',async t=>{ + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-test-cache-link-'));t.after(()=>fs.rm(root,{recursive:true,force:true})); + await fs.mkdir(path.join(root,'outside'));await fs.symlink(path.join(root,'outside'),path.join(root,'updates')); + const f=await fixture(t,{app:{isPackaged:true,getPath:()=>root}});await f.coordinator.start();await f.coordinator.download(); + assert.notEqual(f.coordinator.getStatus().state,'Ready');assert.equal(f.validationCalls(),0); + const wrong=await fixture(t,{distribution:{...distribution,repository:'foreign/repo'}});await wrong.coordinator.start(); + assert.equal(wrong.coordinator.getStatus().state,'Deferred');assert.equal(wrong.archiveCalls(),0); +}); +async function bundleFixture(t){ + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-testing-bundle-')); + t.after(()=>fs.rm(root,{recursive:true,force:true})); + const bundle=path.join(root,'Rieke OS.app'),runtime=path.join(bundle,'Contents/Resources/runtime'); + const data={ + 'python/bin/python3.11':'candidate code must never execute', + 'mysql/bin/mysqld':'candidate native code must never execute', + 'application/python/workspace_desktop.py':'raise Exception("candidate executed")', + 'frontend/index.html':'frontend', + 'application/rieke-release.json':JSON.stringify({version:'0.1.3',workspace_formats:[1],database_compatibility:1}), + 'application/python/workspace-source.json':JSON.stringify({commit:'b'.repeat(40),python:'3.11.13'})}; + const resources={}; + for(const [name,text]of Object.entries(data)){ + const file=path.join(runtime,name);await fs.mkdir(path.dirname(file),{recursive:true});await fs.writeFile(file,text,{mode:name.includes('/bin/')?0o755:0o644}); + resources[name]={sha256:crypto.createHash('sha256').update(text).digest('hex'),size:Buffer.byteLength(text),executable:name.includes('/bin/')}; + } + const candidate={...current,format:'rieke-desktop-runtime',version:1,application_version:'0.1.3',minimum_macos_version:'14.0',source_dirty:true,source_commit:'a'.repeat(40),parser_commit:'b'.repeat(40),python_version:'3.11.13',resources}; + const manifestFile=path.join(runtime,'runtime-manifest.json');await fs.writeFile(manifestFile,JSON.stringify(candidate)); + await fs.mkdir(path.join(bundle,'Contents/MacOS'));await fs.writeFile(path.join(bundle,'Contents/MacOS/Rieke OS'),'do not execute',{mode:0o755}); + const plist='CFBundleIdentifierorg.riekeos.desktopCFBundleShortVersionString0.1.3LSMinimumSystemVersion14.0'; + await fs.writeFile(path.join(bundle,'Contents/Info.plist'),plist); + await fs.writeFile(path.join(bundle,'Contents/Resources/app.asar'),'test asar'); + const next={...descriptor,asar_sha256:crypto.createHash('sha256').update('test asar').digest('hex'),runtime_manifest_sha256:crypto.createHash('sha256').update(JSON.stringify(candidate)).digest('hex')}; + const bundleDigest=require('../bootstrap.cjs').bundleDigest; + const execute=require('node:util').promisify(require('node:child_process').execFile); + // Tiny fixture is not Mach-O; all boundaries except structural seal checking + // use the actual OS tools. Packaged E2E checks the real seal without this seam. + const run=async(exe,args,options)=>exe==='/usr/bin/codesign'?{stdout:'',stderr:''}:execute(exe,args,options); + return{root,bundle,runtime,descriptor:next,candidate,bundleDigest,run}; +} +test('actual extracted testing bundle permits declared dirty provenance and rejects changed resources/control links',{skip:process.platform!=='darwin'},async t=>{ + const f=await bundleFixture(t); + const options={bundle:f.bundle,descriptor:f.descriptor,manifest:current,hostVersion:'14.2',bundleDigest:f.bundleDigest,run:f.run}; + const result=await inspectTestingBundle(options);assert.equal(result.source_dirty,true);assert.equal(result.developer_id_verified,false); + await assert.rejects(inspectTestingBundle({...options,run:async(exe,args,config)=>{if(exe==='/usr/bin/codesign')throw new Error('damaged structural seal');return f.run(exe,args,config);}}),/damaged structural seal/); + const file=path.join(f.runtime,'frontend/index.html');await fs.appendFile(file,'corrupt');await assert.rejects(inspectTestingBundle(options),/metadata|checksum/);await fs.writeFile(file,'frontend'); + const asar=path.join(f.bundle,'Contents/Resources/app.asar');await fs.rename(asar,asar+'.copy');await fs.symlink('app.asar.copy',asar); + await assert.rejects(inspectTestingBundle(options),/regular contained/); +}); +test('real ZIP preflight/extraction uses installed interpreter and never executes candidate code',{skip:process.platform!=='darwin'},async t=>{ + const f=await bundleFixture(t); + const {promisify}=require('node:util'),run=promisify(require('node:child_process').execFile); + let installedBundle=path.resolve(__dirname,'../dist/mac-arm64/Rieke OS.app'); + try{await fs.access(path.join(installedBundle,'Contents/Resources/runtime/python/bin/python3.11'));} + catch{ + // Small source unit-test fixture only. Packaged E2E always uses real bundled Python. + installedBundle=path.join(f.root,'Current.app'); + const hostPython=(await run('/usr/bin/which',['python3'])).stdout.trim(); + const bin=path.join(installedBundle,'Contents/Resources/runtime/python/bin');await fs.mkdir(bin,{recursive:true}); + await fs.symlink(hostPython,path.join(bin,'python3.11')); + } + const python=path.join(installedBundle,'Contents/Resources/runtime/python/bin/python3.11'); + const archive=path.join(f.root,'Rieke-OS-0.1.3-arm64.zip'); + const generate=String.raw`import os,sys,zipfile +from pathlib import Path +root=Path(sys.argv[1]) +with zipfile.ZipFile(sys.argv[2],'w',zipfile.ZIP_DEFLATED) as z: + for file in root.rglob('*'): + if file.is_file():z.write(file,str(file.relative_to(root.parent))) +`; + await run(python,['-I','-B','-c',generate,f.bundle,archive]); + const body=await fs.readFile(archive); + const next={...f.descriptor,archive:{...descriptor.archive,size:body.length,sha256:crypto.createHash('sha256').update(body).digest('hex'),sha512:crypto.createHash('sha512').update(body).digest('base64')}}; + const executed=[]; + const validated=await validateTestingCandidate({downloadedFile:archive,descriptor:next,manifest:current,hostVersion:'14.2',cacheDirectory:f.root,installedBundle,bundleDigest:f.bundleDigest,run:async(exe,args,options)=>{executed.push(exe);return f.run(exe,args,options);}}); + assert.equal(validated.validated,true);assert.equal(validated.bundle_sha256,await f.bundleDigest(f.bundle)); + assert.ok(executed.every(exe=>exe===python||exe==='/usr/bin/ditto'||exe==='/usr/libexec/PlistBuddy'||exe==='/usr/bin/codesign')); + assert.ok(!executed.some(exe=>exe.startsWith(f.bundle))); + await fs.writeFile(path.join(validated.bundle_path,'extra-after-validation'),'changed full app closure'); + await assert.rejects(revalidateTestingCandidate({candidate:validated,descriptor:next,manifest:current,hostVersion:'14.2',run:f.run}),/Prepared app bundle changed/); +}); diff --git a/desktop/test/updater.test.cjs b/desktop/test/updater.test.cjs new file mode 100644 index 0000000..36e04a9 --- /dev/null +++ b/desktop/test/updater.test.cjs @@ -0,0 +1,121 @@ +'use strict'; +const test = require('node:test'); +const assert = require('node:assert/strict'); +const {EventEmitter} = require('node:events'); +const fs = require('node:fs/promises'); +const os = require('node:os'); +const path = require('node:path'); +const {createUpdateCoordinator} = require('../updater.cjs'); +const {compatibleCandidate, compatibleMacMinimum, safeResource, compareVersions, verifyResources, ARCHIVE_CHECK} = require('../updater-validation.cjs'); +const manifest = {format: 'rieke-desktop-runtime', version: 1, source_dirty:false,source_commit:'a'.repeat(40),parser_commit:'b'.repeat(40),application_version: '1.0.0', platform: 'darwin', architecture: 'arm64', mysql_version: '8.4.2', workspace_formats: [1], database_compatibility: 1, resources: {'file': {sha256: 'a'.repeat(64), size: 0}}}; +test('candidate rejects migrations, downgrades, prereleases and foreign platforms', () => { + const next = {...manifest, application_version: '1.1.0'}; + assert.equal(compatibleCandidate(next, manifest, '1.1.0'), next); + for (const patch of [{application_version: '0.9.0'}, {application_version: '1.1.0-beta'}, {mysql_version: '9.0.0'}, {database_compatibility: 2}, {workspace_formats: [2]}, {architecture: 'x64'}, {resources: {}}]) assert.throws(() => compatibleCandidate({...next, ...patch}, manifest, patch.application_version || '1.1.0')); + assert.equal(compareVersions('1.10.0', '1.9.9'), 1); + assert.equal(compatibleMacMinimum('14.0','14.2.1'),true); + assert.throws(()=>compatibleMacMinimum('15.0','14.2.1')); + for (const unsafe of ['../outside', '/absolute', 'a/../../outside', 'a\\b', 'a//b', './a']) assert.throws(() => safeResource('/tmp/runtime', unsafe)); +}); +test('resource verification rejects a symlink which resolves outside the bundle', async t => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-resource-test-')); + t.after(() => fs.rm(root, {recursive: true, force: true})); + await fs.symlink('/etc/hosts', path.join(root, 'escape')); + await assert.rejects(verifyResources(root, {escape: {symlink: '/etc/hosts'}}), /escapes/); +}); +test('archive preflight rejects traversal and escaping symlinks before extraction', async t => { + const {spawnSync} = require('node:child_process'); + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-archive-test-')); + t.after(() => fs.rm(root, {recursive: true, force: true})); + const bundledPython = path.resolve(__dirname, '../build/runtime/python/bin/python3.11'); + const python = require('node:fs').existsSync(bundledPython) ? bundledPython : 'python3'; + const generate = String.raw` +import sys,zipfile,stat +with zipfile.ZipFile(sys.argv[1],'w') as archive: + kind=sys.argv[2] + if kind=='traversal': archive.writestr('../escape','data') + elif kind=='link': + info=zipfile.ZipInfo('Rieke OS.app/escape');info.create_system=3;info.external_attr=(stat.S_IFLNK|0o777)<<16 + archive.writestr(info,'../../escape');archive.writestr('Rieke OS.app/escape/file','data') + elif kind=='safe': + archive.writestr('Rieke OS.app/Contents/file','data') + info=zipfile.ZipInfo('Rieke OS.app/Contents/link');info.create_system=3;info.external_attr=(stat.S_IFLNK|0o777)<<16 + archive.writestr(info,'file') +`; + for (const kind of ['traversal','link','safe']) { + const filename = path.join(root, kind+'.zip'); + assert.equal(spawnSync(python,['-I','-B','-c',generate,filename,kind],{encoding:'utf8'}).status,0); + const result=spawnSync(python,['-I','-B','-c',ARCHIVE_CHECK,filename],{encoding:'utf8'}); + assert.equal(result.status,kind==='safe'?0:1); + } +}); +async function fixture(t, options = {}) { + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-updater-test-')); + // Receipt writes are serialized; remove after they have had a turn to settle. + t.after(async () => {coordinator.stop(); await new Promise(resolve => setTimeout(resolve, 30)); await fs.rm(dir, {recursive: true, force: true});}); + const updater = new EventEmitter(); + updater.setFeedURL = value => {updater.feed = value;}; + updater.checkForUpdates = async () => {}; + let installs = 0, drains = 0; + updater.quitAndInstall = () => {installs++;}; + const coordinator = createUpdateCoordinator({app: {isPackaged: true, getPath: () => dir}, manifest, updater, + verifyInstalled: async () => ({team: 'TESTTEAM', identifier: 'org.riekeos.desktop'}), + verifyCandidate: async ({version}) => ({version, validated: true}), + retainPrevious: async () => {}, + prepareQuit: async () => {drains++; return {ready: false};}, + timers: {setTimeout: () => 1, clearTimeout: () => {}}, ...options}); + await coordinator.start(); + return {coordinator, updater, installs: () => installs, drains: () => drains}; +} +test('source and unsigned builds have no install authority', async t => { + const {coordinator, updater} = await fixture(t, {enabled: false}); + assert.equal(coordinator.getStatus().state, 'Deferred'); + assert.equal(updater.feed, undefined); + assert.equal((await coordinator.installPrepared()).ready, false); +}); +test('quiet downloads require validation and every drain acknowledgment before install', {skip: process.platform !== 'darwin' || process.arch !== 'arm64'}, async t => { + let allowDrain = false; + const {coordinator, updater, installs} = await fixture(t, {prepareQuit: async () => ({ready: allowDrain})}); + assert.equal(updater.autoInstallOnAppQuit, false); + assert.equal(updater.allowDowngrade, false); + assert.equal(updater.allowPrerelease, false); + assert.equal(updater.feed.repo, 'Rieke-OS'); + updater.emit('update-downloaded', {version: '1.1.0', downloadedFile: '/cache/update.zip'}); + await new Promise(resolve => setImmediate(resolve)); + assert.equal(coordinator.getStatus().state, 'Ready'); + assert.equal(coordinator.getStatus().native_staging_verified, false); + assert.equal((await coordinator.installPrepared()).ready, false); + assert.equal(installs(), 0); + assert.equal(coordinator.getStatus().state, 'Ready'); + updater.emit('error', new Error('Network failure with secret URL')); + assert.equal(coordinator.getStatus().state, 'Ready'); + assert.equal(coordinator.getStatus().available, '1.1.0'); + assert.ok(!JSON.stringify(coordinator.getStatus()).includes('secret')); + allowDrain = true; + const results = await Promise.all([coordinator.installPrepared(), coordinator.installPrepared()]); + assert.ok(results.every(result => result.installing)); + assert.equal(installs(), 1); +}); +test('rejected candidate never becomes ready or installs', {skip: process.platform !== 'darwin' || process.arch !== 'arm64'}, async t => { + const {coordinator, updater, installs} = await fixture(t, {verifyCandidate: async () => {throw new Error('invalid signature');}}); + updater.emit('update-downloaded', {version: '1.1.0'}); + await new Promise(resolve => setImmediate(resolve)); + assert.equal(coordinator.getStatus().state, 'Deferred'); + assert.equal((await coordinator.installPrepared()).ready, false); + assert.equal(installs(), 0); +}); +test('cache mutation during real drain cannot authorize the native installer', {skip: process.platform !== 'darwin' || process.arch !== 'arm64'}, async t => { + const crypto=require('node:crypto'); + const directory=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-drain-cache-test-')); + t.after(()=>fs.rm(directory,{recursive:true,force:true})); + const downloadedFile=path.join(directory,'candidate.zip');await fs.writeFile(downloadedFile,'verified fixture'); + const archive_sha256=crypto.createHash('sha256').update('verified fixture').digest('hex'); + let recovered=false; + const {coordinator,updater,installs}=await fixture(t,{ + verifyCandidate:async({version})=>({version,downloadedFile,archive_sha256}), + prepareQuit:async()=>{await fs.writeFile(downloadedFile,'changed during drain');return {ready:true};}, + onInstallationFailure:()=>{recovered=true;}}); + updater.emit('update-downloaded',{version:'1.1.0'});await new Promise(resolve=>setImmediate(resolve)); + assert.equal((await coordinator.installPrepared()).ready,false); + assert.equal(installs(),0);assert.equal(recovered,true);assert.equal(coordinator.getStatus().state,'Deferred'); +}); diff --git a/desktop/testing-install.cjs b/desktop/testing-install.cjs new file mode 100644 index 0000000..1b49612 --- /dev/null +++ b/desktop/testing-install.cjs @@ -0,0 +1,189 @@ +'use strict'; +// Explicit unsigned-testing distribution only. Integrity is checked locally; +// macOS quarantine and Gatekeeper decisions are left intact. +const fs=require('./physical-fs.cjs').promises; +const path=require('node:path'); +const os=require('node:os'); +const {promisify}=require('node:util'); +const {execFile,spawn}=require('node:child_process'); +const {createHash,randomUUID}=require('node:crypto'); +const runFile=promisify(execFile); +const {APP_ID,enclosingApp,bundleDigest,installCompleteBundle,readBundleManifest,compatibleManifest,assertNotRunning,verifyTestingBundle}=require('./bootstrap.cjs'); +const {compareVersions,stableVersion,verifyResources}=require('./updater-validation.cjs'); +const READY='RIEKE_TESTING_INSTALL_READY='; +async function sha256(file){ + const digest=createHash('sha256'),handle=await fs.open(file,'r'); + try{for await(const chunk of handle.createReadStream())digest.update(chunk);}finally{await handle.close();} + return digest.digest('hex'); +} +async function privateReceipt(receiptPath,{previous=false}={}){ + const info=await fs.lstat(receiptPath); + if(!info.isFile()||info.isSymbolicLink()||info.uid!==process.getuid()||(info.mode&0o077)||info.size>65536)throw new Error('Update receipt must be a private current-user-owned regular file'); + const parent=await fs.lstat(path.dirname(receiptPath)); + if(!parent.isDirectory()||parent.isSymbolicLink()||parent.uid!==process.getuid())throw new Error('Update receipt directory must be current-user owned'); + const value=JSON.parse(await fs.readFile(receiptPath,'utf8')); + if(value.format!==(previous?'rieke-unsigned-testing-previous':'rieke-unsigned-testing-update')||value.version!==1||value.channel!=='unsigned-testing'||value.identifier!==APP_ID||(!previous&&value.validated!==true))throw new Error('Unsigned testing update receipt is invalid'); + return value; +} +async function processCreationIdentity(pid,currentExecutable,run=runFile){ + if(!Number.isSafeInteger(pid)||pid<=0)throw new Error('Current app process identity is invalid'); + const bundle=enclosingApp(currentExecutable); + if(!bundle)throw new Error('Current app executable must be an installed complete bundle'); + const python=path.join(bundle,'Contents/Resources/runtime/python/bin/python3.11'); + const code='import json,os,psutil,sys\ntry:\n p=psutil.Process(int(sys.argv[1])); value={"pid":p.pid,"created_at":p.create_time(),"executable":os.path.realpath(p.exe()),"alive":p.status()!=psutil.STATUS_ZOMBIE}\nexcept psutil.NoSuchProcess: value={"pid":int(sys.argv[1]),"alive":False}\nprint("RIEKE_PROCESS_IDENTITY="+json.dumps(value))'; + const result=await run(python,['-I','-B','-c',code,String(pid)],{timeout:15000,env:{...process.env,PYTHONDONTWRITEBYTECODE:'1',PYTHONNOUSERSITE:'1'}}); + const line=result.stdout.split('\n').find(value=>value.startsWith('RIEKE_PROCESS_IDENTITY=')); + if(!line)throw new Error('Current app process identity is unavailable'); + const identity=JSON.parse(line.slice('RIEKE_PROCESS_IDENTITY='.length)); + if(identity.pid!==pid||typeof identity.alive!=='boolean'||(identity.alive&&(!Number.isFinite(identity.created_at)||typeof identity.executable!=='string')))throw new Error('Current app process identity is invalid'); + return identity; +} +async function ownedCachePath(file,cache,{directory=false}={}){ + const info=await fs.lstat(file),physical=await fs.realpath(file); + if(info.uid!==process.getuid()||info.isSymbolicLink()||!(directory?info.isDirectory():info.isFile())||!physical.startsWith(cache+path.sep))throw new Error('Prepared update must remain in its owned receipt cache'); + return physical; +} +async function atomicPrivateJSON(file,value){ + const temporary=file+'.'+randomUUID(); + const handle=await fs.open(temporary,'wx',0o600); + try{await handle.writeFile(JSON.stringify(value,null,2)+'\n');await handle.sync();}finally{await handle.close();} + try{await fs.rename(temporary,file);const directory=await fs.open(path.dirname(file),'r');try{await directory.sync();}finally{await directory.close();}} + finally{await fs.rm(temporary,{force:true});} +} +async function validatePrepared({receiptPath,currentExecutable,run=runFile,requireParent=true}){ + const receipt=await privateReceipt(receiptPath); + const restoring=receipt.operation==='restore'; + if(receipt.operation!==undefined&&!['update','restore'].includes(receipt.operation))throw new Error('Unsigned testing operation is invalid'); + const executable=await fs.realpath(currentExecutable),installed=enclosingApp(executable); + if(!installed||await fs.realpath(receipt.install_path)!==installed||await fs.realpath(receipt.current_executable)!==executable||!Number.isSafeInteger(receipt.current_pid)||receipt.current_pid<=0||!Number.isFinite(receipt.current_created_at))throw new Error('Update does not belong to this exact installed app'); + for(const field of [...(restoring?[]:['archive_sha256']),'bundle_sha256','runtime_manifest_sha256','current_manifest_sha256'])if(!/^[a-f0-9]{64}$/.test(receipt[field]||''))throw new Error('Update receipt checksum is invalid'); + const cache=await fs.realpath(path.dirname(receiptPath)); + if(path.basename(cache)!=='unsigned-testing'||path.basename(path.dirname(cache))!=='updates')throw new Error('Update cache does not belong to the current application profile'); + const userData=path.dirname(path.dirname(cache)),profile=await fs.lstat(userData); + if(profile.isSymbolicLink()||!profile.isDirectory()||profile.uid!==process.getuid())throw new Error('Current application profile ownership differs'); + let bundle; + if(restoring){ + const prior=await privateReceipt(path.join(cache,'previous.json'),{previous:true}); + const expected=path.join(path.dirname(installed),'.Rieke OS.previous.app'); + const info=await fs.lstat(expected); + if(info.isSymbolicLink()||!info.isDirectory()||info.uid!==process.getuid()||await fs.realpath(receipt.bundle_path)!==expected||prior.previous_path!==expected||prior.install_path!==installed||prior.current_version!==receipt.current_version||prior.previous_version!==receipt.target_version||prior.previous_bundle_sha256!==receipt.bundle_sha256||prior.previous_manifest_sha256!==receipt.runtime_manifest_sha256)throw new Error('Restore does not identify the retained verified previous app'); + bundle=expected; + }else{ + const archive=await ownedCachePath(receipt.archive_path,cache); + bundle=await ownedCachePath(receipt.bundle_path,cache,{directory:true}); + if(await sha256(archive)!==receipt.archive_sha256)throw new Error('Prepared update archive or bundle checksum differs'); + } + if(await bundleDigest(bundle)!==receipt.bundle_sha256)throw new Error('Prepared update archive or bundle checksum differs'); + const manifestPath=path.join(bundle,'Contents/Resources/runtime/runtime-manifest.json'); + const currentPath=path.join(installed,'Contents/Resources/runtime/runtime-manifest.json'); + if(await sha256(manifestPath)!==receipt.runtime_manifest_sha256||await sha256(currentPath)!==receipt.current_manifest_sha256)throw new Error('Prepared update or installed runtime manifest differs'); + const current=await readBundleManifest(installed),candidate=await readBundleManifest(bundle); + stableVersion(receipt.target_version); + if(current.application_version!==receipt.current_version||candidate.application_version!==receipt.target_version||(!restoring&&compareVersions(receipt.target_version,receipt.current_version)<=0)||!compatibleManifest(candidate,current))throw new Error('Unsigned update version or data compatibility differs'); + await verifyResources(path.join(installed,'Contents/Resources/runtime'),current.resources); + await verifyResources(path.join(bundle,'Contents/Resources/runtime'),candidate.resources); + await verifyTestingBundle(bundle,run); + if(requireParent){ + const identity=await processCreationIdentity(receipt.current_pid,executable,run); + if(!identity.alive||identity.created_at!==receipt.current_created_at||await fs.realpath(identity.executable)!==executable)throw new Error('Current app process ownership changed'); + } + return {receipt,installed,executable,bundle,cache,current,candidate,userData}; +} +async function applyTestingInstall({receiptPath,currentExecutable=process.execPath,run=runFile,publishReady=packet=>process.stdout.write(READY+JSON.stringify(packet)+'\n'),timeoutMs=90000,pollMs=200}){ + const prepared=await validatePrepared({receiptPath,currentExecutable,run}); + const {receipt,installed,executable,bundle,cache,current,userData}=prepared; + const openArguments=['-n','-a',installed,'--env','HOME='+os.homedir(),'--args','--user-data-dir='+userData]; + publishReady({pid:process.pid,current_pid:receipt.current_pid,version:receipt.target_version,archive_sha256:receipt.archive_sha256}); + const deadline=Date.now()+timeoutMs; + for(;;){ + const identity=await processCreationIdentity(receipt.current_pid,executable,run); + if(!identity.alive)break; + if(identity.created_at!==receipt.current_created_at||await fs.realpath(identity.executable)!==executable)throw new Error('Current app process ownership changed while waiting for exit'); + if(Date.now()>=deadline)throw new Error('Current app exit was not acknowledged; installation deferred'); + await new Promise(resolve=>setTimeout(resolve,pollMs)); + } + // Cached data is checked again after actual exit, before touching installation. + await validatePrepared({receiptPath,currentExecutable,run,requireParent:false}); + const priorDigest=await bundleDigest(installed); + const result=await installCompleteBundle({source:bundle,destination:installed,distribution:{channel:'unsigned-testing'},expectedBundleSha256:receipt.bundle_sha256,run,allowRollback:true,ignorePid:process.pid}); + await atomicPrivateJSON(path.join(cache,'previous.json'),{format:'rieke-unsigned-testing-previous',version:1,channel:'unsigned-testing',identifier:APP_ID, + install_path:installed,previous_path:result.previous,previous_version:current.application_version,previous_bundle_sha256:priorDigest, + previous_manifest_sha256:receipt.current_manifest_sha256,current_version:receipt.target_version}); + try{await run('/usr/bin/open',openArguments);} + catch(error){ + // A refused launch may be Gatekeeper. Preserve its attributes and return to + // the verified previous app; never clear quarantine or suppress OS approval. + if(!result.previous||await bundleDigest(result.previous)!==priorDigest)throw error; + await assertNotRunning(installed,run,process.pid); + const failed=path.join(cache,'failed-candidate-'+randomUUID()+'.app'); + await fs.rename(installed,failed); + try{await fs.rename(result.previous,installed);}catch(rollbackError){await fs.rename(failed,installed);throw rollbackError;} + if(await bundleDigest(installed)!==priorDigest)throw new Error('Restored previous application checksum differs'); + await fs.rm(path.join(cache,'previous.json'),{force:true}); + await run('/usr/bin/open',openArguments); + const outcome={state:'Restored',destination:installed,version:current.application_version,failedCandidateRetained:true}; + await atomicPrivateJSON(receiptPath+'.result.json',outcome);return outcome; + } + const outcome={state:receipt.operation==='restore'?'Restored':'Installed',destination:installed,previous:result.previous,version:receipt.target_version}; + await atomicPrivateJSON(receiptPath+'.result.json',outcome); + return outcome; +} +async function launchTestingInstall({receiptPath,currentExecutable=process.execPath,currentPid=process.pid,run=runFile,spawnHelper=spawn,readyTimeoutMs=150000}){ + const prepared=await validatePrepared({receiptPath,currentExecutable,run}); + if(prepared.receipt.current_pid!==currentPid||!path.resolve(__filename).startsWith(prepared.installed+path.sep))throw new Error('Install helper must originate from this exact current app'); + const script=path.join(__dirname,'testing-install.cjs'); + const child=spawnHelper(prepared.executable,[script,'--apply',receiptPath],{detached:true,stdio:['ignore','pipe','pipe'],cwd:prepared.cache, + env:{HOME:process.env.HOME,TMPDIR:process.env.TMPDIR,LANG:process.env.LANG||'en_US.UTF-8',PATH:'/usr/bin:/bin',ELECTRON_RUN_AS_NODE:'1'}}); + const resultPath=receiptPath+'.result.json'; + await new Promise((resolve,reject)=>{ + let buffer='',done=false; + const timer=setTimeout(()=>finish(new Error('Install helper readiness was not acknowledged; current app stays open')),readyTimeoutMs); + const finish=error=>{if(done)return;done=true;clearTimeout(timer);if(error)reject(error);else resolve();}; + child.once('error',finish);child.once('exit',()=>finish(new Error('Install helper exited before readiness acknowledgement'))); + child.stderr?.on('data',()=>{}); + child.stdout.on('data',chunk=>{ + buffer+=chunk.toString('utf8');if(buffer.length>65536)return finish(new Error('Install helper readiness packet exceeded bounds')); + let end; + while((end=buffer.indexOf('\n'))>=0){ + const line=buffer.slice(0,end);buffer=buffer.slice(end+1); + if(!line.startsWith(READY))continue; + try{const packet=JSON.parse(line.slice(READY.length)); + if(packet.pid!==child.pid||packet.current_pid!==currentPid||packet.version!==prepared.receipt.target_version||packet.archive_sha256!==prepared.receipt.archive_sha256)throw new Error('Install helper readiness identity differs'); + finish(); + }catch(error){finish(error);} + } + }); + }); + child.stdout.unref?.();child.stderr.unref?.();child.unref(); + return {ready:true,helperPid:child.pid,resultPath}; +} +async function restoreTestingPriorBundle({app,manifest,prepareQuit,authorizeQuit,run=runFile,spawnHelper=spawn}){ + if(!app?.isPackaged)throw new Error('Restore requires the installed unsigned testing application'); + const executable=await fs.realpath(app.getPath('exe')),installed=enclosingApp(executable); + const cache=path.join(app.getPath('userData'),'updates','unsigned-testing'); + const prior=await privateReceipt(path.join(cache,'previous.json'),{previous:true}); + const currentPath=path.join(installed,'Contents/Resources/runtime/runtime-manifest.json'); + if(prior.install_path!==installed||prior.current_version!==manifest.application_version)throw new Error('Retained previous app does not belong to this installed version'); + const identity=await processCreationIdentity(process.pid,executable,run); + if(!identity.alive||await fs.realpath(identity.executable)!==executable)throw new Error('Current app process identity differs'); + const receiptPath=path.join(cache,'restore-'+randomUUID()+'.json'); + await atomicPrivateJSON(receiptPath,{format:'rieke-unsigned-testing-update',version:1,channel:'unsigned-testing',identifier:APP_ID,validated:true,operation:'restore', + install_path:installed,current_executable:executable,current_pid:process.pid,current_created_at:identity.created_at, + current_version:manifest.application_version,target_version:prior.previous_version,current_manifest_sha256:await sha256(currentPath), + runtime_manifest_sha256:prior.previous_manifest_sha256,bundle_path:prior.previous_path,bundle_sha256:prior.previous_bundle_sha256,archive_path:null,archive_sha256:null}); + await validatePrepared({receiptPath,currentExecutable:executable,run}); + const result=await prepareQuit();if(result?.ready!==true)return result; + const prepared=await launchTestingInstall({receiptPath,currentExecutable:executable,currentPid:process.pid,run,spawnHelper}); + authorizeQuit();app.quit();return {...prepared,restoring:true}; +} +async function main(){ + if(process.env.ELECTRON_RUN_AS_NODE!=='1'||process.argv[2]!=='--apply'||process.argv.length!==4)throw new Error('Install helper invocation is invalid'); + const receiptPath=process.argv[3]; + try{await applyTestingInstall({receiptPath});} + catch(error){ + try{await privateReceipt(receiptPath);await atomicPrivateJSON(receiptPath+'.result.json',{state:'Deferred',error:'Testing update could not complete; installation and macOS protections were preserved.',error_type:error.name});}catch{} + process.exitCode=1; + } +} +if(require.main===module)main().catch(()=>{process.exitCode=1;}); +module.exports={processCreationIdentity,applyTestingInstall,launchTestingInstall,restoreTestingPriorBundle,sha256,bundleDigest}; diff --git a/desktop/testing-update-validation.cjs b/desktop/testing-update-validation.cjs new file mode 100644 index 0000000..c209b1e --- /dev/null +++ b/desktop/testing-update-validation.cjs @@ -0,0 +1,127 @@ +'use strict'; +const physicalFS=require('./physical-fs.cjs'); +const fs=physicalFS.promises,path=require('node:path'),crypto=require('node:crypto'); +const {constants}=physicalFS; +const {promisify}=require('node:util'); +const runFile=promisify(require('node:child_process').execFile); +const {compareVersions,compatibleMacMinimum,verifyResources,ARCHIVE_CHECK}=require('./updater-validation.cjs'); +const REPOSITORY='maxwellsdm1867/Rieke-OS'; +function approvedURL(value,kind='asset',redirect=false){ + const url=new URL(value); + if(url.protocol!=='https:'||url.username||url.password||url.hash||(url.port&&url.port!=='443'))throw new Error('Only public GitHub HTTPS downloads are accepted.'); + if(kind==='api'){ + if(url.hostname!=='api.github.com'||url.pathname!==`/repos/${REPOSITORY}/releases`)throw new Error('Unexpected release API.'); + }else if(url.hostname==='github.com'){ + if(!url.pathname.startsWith(`/${REPOSITORY}/releases/download/`)||url.search||decodeURIComponent(url.pathname).split('/').some(p=>p==='..'||p==='.')||/%2f|%5c/i.test(url.pathname))throw new Error('Unexpected release asset.'); + }else if(!redirect||!['release-assets.githubusercontent.com','objects.githubusercontent.com','github-releases.githubusercontent.com'].includes(url.hostname))throw new Error('Unexpected asset redirect.'); + return true; +} +function validateDescriptor(value,current,hostVersion){ + if(!value||value.format!=='rieke-desktop-test-release'||value.version!==1||value.channel!=='unsigned-testing'||value.repository!==REPOSITORY)throw new Error('Unexpected testing release provenance.'); + if(compareVersions(value.application_version,current.application_version)<=0)throw new Error('Testing update must be newer than the installed app.'); + if(value.platform!=='darwin'||value.architecture!=='arm64'||current.platform!==value.platform||current.architecture!==value.architecture)throw new Error('Unsupported testing platform.'); + if(value.mysql_version!==current.mysql_version||value.database_compatibility!==current.database_compatibility||!Array.isArray(value.workspace_formats)||!Array.isArray(current.workspace_formats)||!current.workspace_formats.every(f=>value.workspace_formats.includes(f)))throw new Error('Testing update requires a data migration.'); + compatibleMacMinimum(value.minimum_macos_version,hostVersion); + const archive=value.archive; + if(!archive||archive.filename!==`Rieke-OS-${value.application_version}-arm64.zip`||!Number.isSafeInteger(archive.size)||archive.size<=0||archive.size>2*1024**3||!/^[a-f0-9]{64}$/.test(archive.sha256||'')||!/^[A-Za-z0-9+/]{86}==$/.test(archive.sha512||'')||Buffer.from(archive.sha512,'base64').length!==64)throw new Error('Invalid testing archive metadata.'); + if(!/^[a-f0-9]{64}$/.test(value.asar_sha256||'')||!/^[a-f0-9]{64}$/.test(value.runtime_manifest_sha256||''))throw new Error('Incomplete testing app checksums.'); + return value; +} +async function hashFile(file,algorithm='sha256'){ + const handle=await fs.open(file,constants.O_RDONLY|constants.O_NOFOLLOW); + try{ + const stat=await handle.stat();if(!stat.isFile())throw new Error('Expected a regular file.'); + const hash=crypto.createHash(algorithm);for await(const chunk of handle.createReadStream({autoClose:false}))hash.update(chunk); + return hash.digest(algorithm==='sha512'?'base64':'hex'); + }finally{await handle.close();} +} +async function verifyArchive(file,descriptor){ + const info=await fs.lstat(file); + if(!info.isFile()||info.isSymbolicLink()||info.uid!==process.getuid()||info.size!==descriptor.archive.size)throw new Error('Prepared archive size or ownership changed.'); + if(await hashFile(file)!==descriptor.archive.sha256||await hashFile(file,'sha512')!==descriptor.archive.sha512)throw new Error('Testing archive checksum failed.'); +} +async function ensurePrivateCache(userData){ + await fs.mkdir(userData,{recursive:true,mode:0o700}); + let directory=userData; + for(const part of ['', 'updates','unsigned-testing']){ + if(part)directory=path.join(directory,part); + await fs.mkdir(directory,{recursive:true,mode:0o700}); + const stat=await fs.lstat(directory); + if(!stat.isDirectory()||stat.isSymbolicLink()||stat.uid!==process.getuid())throw new Error('Update cache must be owned and contain no directory links.'); + if(part)await fs.chmod(directory,0o700); + } + return directory; +} +async function regularContained(bundle,relative){ + const file=path.join(bundle,relative),stat=await fs.lstat(file),resolved=await fs.realpath(file),root=await fs.realpath(bundle); + if(!stat.isFile()||stat.isSymbolicLink()||!resolved.startsWith(root+path.sep))throw new Error('App control files must be regular contained files.'); + let parent=path.dirname(file); + while(parent!==bundle){if((await fs.lstat(parent)).isSymbolicLink())throw new Error('App control directories cannot be links.');parent=path.dirname(parent);} + return file; +} +async function inspectTestingBundle({bundle,descriptor,manifest,hostVersion,run=runFile,bundleDigest}){ + validateDescriptor(descriptor,manifest,hostVersion); + const root=await fs.realpath(bundle); + if((await fs.lstat(bundle)).isSymbolicLink())throw new Error('Candidate app cannot be a symlink.'); + async function links(directory){ + for(const entry of await fs.readdir(directory,{withFileTypes:true})){ + const file=path.join(directory,entry.name); + if(entry.isSymbolicLink()){ + const target=await fs.readlink(file),physical=await fs.realpath(file); + if(path.isAbsolute(target)||!physical.startsWith(root+path.sep))throw new Error('App has an escaping link.'); + }else if(entry.isDirectory())await links(file); + else if(!entry.isFile())throw new Error('App has a special filesystem node.'); + } + } + await links(bundle); + const plist=await regularContained(bundle,'Contents/Info.plist'); + const entry=await regularContained(bundle,'Contents/MacOS/Rieke OS'); + if(!((await fs.stat(entry)).mode&0o111))throw new Error('App entry is not executable.'); + const asar=await regularContained(bundle,'Contents/Resources/app.asar'); + const manifestPath=await regularContained(bundle,'Contents/Resources/runtime/runtime-manifest.json'); + if(await hashFile(asar)!==descriptor.asar_sha256||await hashFile(manifestPath)!==descriptor.runtime_manifest_sha256)throw new Error('Testing app identity checksums differ.'); + const candidate=JSON.parse(await fs.readFile(manifestPath,'utf8')); + if(candidate.format!=='rieke-desktop-runtime'||candidate.version!==1||candidate.application_version!==descriptor.application_version||candidate.platform!==descriptor.platform||candidate.architecture!==descriptor.architecture||candidate.mysql_version!==descriptor.mysql_version||candidate.database_compatibility!==descriptor.database_compatibility||JSON.stringify(candidate.workspace_formats)!==JSON.stringify(descriptor.workspace_formats)||candidate.minimum_macos_version!==descriptor.minimum_macos_version||!/^[a-f0-9]{40}$/.test(candidate.source_commit||'')||!/^[a-f0-9]{40}$/.test(candidate.parser_commit||'')||typeof candidate.source_dirty!=='boolean'||!candidate.resources||typeof candidate.resources!=='object'||Array.isArray(candidate.resources)||!Object.keys(candidate.resources).length)throw new Error('Testing runtime differs from its descriptor.'); + for(const [key,expected] of [['CFBundleIdentifier','org.riekeos.desktop'],['CFBundleShortVersionString',descriptor.application_version],['LSMinimumSystemVersion',descriptor.minimum_macos_version]]){ + const result=await run('/usr/libexec/PlistBuddy',['-c',`Print :${key}`,plist]); + if(result.stdout.trim()!==expected)throw new Error('App property list differs from testing metadata.'); + } + const runtime=path.join(bundle,'Contents/Resources/runtime'); + for(const relative of ['python/bin/python3.11','mysql/bin/mysqld','application/python/workspace_desktop.py','frontend/index.html']){ + if(!candidate.resources[relative])throw new Error('Required private runtime entry is absent.'); + await regularContained(bundle,'Contents/Resources/runtime/'+relative); + } + for(const relative of ['python/bin/python3.11','mysql/bin/mysqld'])if(candidate.resources[relative].executable!==true)throw new Error('Private native runtime entry is not executable.'); + const releasePath=await regularContained(bundle,'Contents/Resources/runtime/application/rieke-release.json'); + const sourcePath=await regularContained(bundle,'Contents/Resources/runtime/application/python/workspace-source.json'); + const release=JSON.parse(await fs.readFile(releasePath,'utf8')),source=JSON.parse(await fs.readFile(sourcePath,'utf8')); + if(release.version!==candidate.application_version||release.database_compatibility!==candidate.database_compatibility||JSON.stringify(release.workspace_formats)!==JSON.stringify(candidate.workspace_formats)||source.commit!==candidate.parser_commit||source.python!==candidate.python_version)throw new Error('Runtime compatibility differs from application declarations.'); + await verifyResources(runtime,candidate.resources); + // Structural integrity accepts an ad-hoc testing seal; this is not a + // Developer ID, notarization, or Gatekeeper authorization assertion. + await run('/usr/bin/codesign',['--verify','--deep','--strict',bundle],{timeout:180000}); + bundleDigest||=require('./testing-install.cjs').bundleDigest; + return {version:descriptor.application_version,bundle_path:bundle,bundle_sha256:await bundleDigest(bundle),runtime_manifest_sha256:descriptor.runtime_manifest_sha256,validated:true,source_dirty:candidate.source_dirty,trust:'official-repository-https-checksums',developer_id_verified:false,native_staging_verified:false,startup_health_verified:false}; +} +async function validateTestingCandidate({downloadedFile,descriptor,manifest,cacheDirectory,installedBundle,hostVersion,run=runFile,bundleDigest}){ + await verifyArchive(downloadedFile,descriptor); + const temporary=await fs.mkdtemp(path.join(cacheDirectory,'candidate-')); + try{ + const python=path.join(installedBundle,'Contents/Resources/runtime/python/bin/python3.11'); + // Only the current trusted Python parses the ZIP. No candidate code executes. + await run(python,['-I','-B','-c',ARCHIVE_CHECK,downloadedFile],{timeout:30000}); + await run('/usr/bin/ditto',['-x','-k',downloadedFile,temporary],{timeout:180000}); + const entries=await fs.readdir(temporary); + if(entries.length!==1||entries[0]!=='Rieke OS.app')throw new Error('Testing archive must contain exactly Rieke OS.app.'); + const validated=await inspectTestingBundle({bundle:path.join(temporary,entries[0]),descriptor,manifest,hostVersion,run,bundleDigest}); + await verifyArchive(downloadedFile,descriptor); + return {...validated,downloadedFile,archive_sha256:descriptor.archive.sha256,candidate_directory:temporary}; + }catch(error){await fs.rm(temporary,{recursive:true,force:true});throw error;} +} +async function revalidateTestingCandidate({candidate,descriptor,manifest,hostVersion,run=runFile,bundleDigest}){ + await verifyArchive(candidate.downloadedFile,descriptor); + const result=await inspectTestingBundle({bundle:candidate.bundle_path,descriptor,manifest,hostVersion,run,bundleDigest}); + if(result.bundle_sha256!==candidate.bundle_sha256)throw new Error('Prepared app bundle changed.'); + return result; +} +module.exports={REPOSITORY,approvedURL,validateDescriptor,hashFile,verifyArchive,ensurePrivateCache,inspectTestingBundle,validateTestingCandidate,revalidateTestingCandidate}; diff --git a/desktop/testing-updater.cjs b/desktop/testing-updater.cjs new file mode 100644 index 0000000..59314fd --- /dev/null +++ b/desktop/testing-updater.cjs @@ -0,0 +1,250 @@ +'use strict'; +const physicalFS=require('./physical-fs.cjs'); +const fs=physicalFS.promises,path=require('node:path'),crypto=require('node:crypto'),https=require('node:https'); +const {constants}=physicalFS; +const {promisify}=require('node:util'); +const runFile=promisify(require('node:child_process').execFile); +const {compareVersions}=require('./updater-validation.cjs'); +const {REPOSITORY,approvedURL,validateDescriptor,verifyArchive,ensurePrivateCache,validateTestingCandidate,revalidateTestingCandidate,hashFile}=require('./testing-update-validation.cjs'); +const API=`https://api.github.com/repos/${REPOSITORY}/releases?per_page=100&page=1`; +async function atomicHint(cache,value){ + const temporary=path.join(cache,`prepared-${crypto.randomUUID()}.tmp`),file=path.join(cache,'prepared.json'); + const handle=await fs.open(temporary,'wx',0o600); + try{await handle.writeFile(JSON.stringify(value)+'\n');await handle.sync();}finally{await handle.close();} + try{await fs.rename(temporary,file);const parent=await fs.open(cache,'r');try{await parent.sync();}finally{await parent.close();}} + finally{await fs.rm(temporary,{force:true});} +} +async function hintPath(cache,relative,kind,filename){ + const parts=typeof relative==='string'?relative.split('/'):[]; + if(parts.length!==2||!new RegExp(`^${kind}-[a-zA-Z0-9]{6}$`).test(parts[0])||parts[1]!==filename)throw new Error('Invalid prepared-cache hint.'); + const parent=path.join(cache,parts[0]),file=path.join(parent,parts[1]); + for(const item of [parent,file]){const stat=await fs.lstat(item);if(stat.isSymbolicLink()||stat.uid!==process.getuid())throw new Error('Prepared cache link or ownership differs.');} + if(!((await fs.lstat(parent)).isDirectory())||!((await fs.realpath(file)).startsWith((await fs.realpath(cache))+path.sep)))throw new Error('Prepared cache escapes its owned directory.'); + return file; +} +async function cleanupObsolete(cache,keep=[]){ + // Age protects another still-completing installation. No receipts, previous + // bundles, user-selected paths, or non-cache directories are ever removed. + const retained=new Set(keep.map(file=>path.resolve(file))); + for(const name of await fs.readdir(cache)){ + if(!/^(?:download|candidate)-[a-zA-Z0-9]{6}$/.test(name))continue; + const file=path.join(cache,name),info=await fs.lstat(file); + if(!retained.has(file)&&info.isDirectory()&&!info.isSymbolicLink()&&info.uid===process.getuid()&&Date.now()-info.mtimeMs>24*3600000)await fs.rm(file,{recursive:true,force:true}); + } +} +function httpsTransport(url,{kind='asset',redirects=0}={}){ + approvedURL(url,kind,redirects>0); + return new Promise((resolve,reject)=>{ + const request=https.get(url,{headers:{'User-Agent':'Rieke-OS-desktop-testing-updater','Accept':kind==='api'?'application/vnd.github+json':'application/octet-stream'}},response=>{ + if([301,302,303,307,308].includes(response.statusCode)){ + response.resume(); + if(redirects>=5||!response.headers.location)return reject(new Error('Release redirect limit.')); + let next;try{next=new URL(response.headers.location,url).href;approvedURL(next,kind,true);}catch(error){return reject(error);} + resolve(httpsTransport(next,{kind,redirects:redirects+1})); + }else resolve({statusCode:response.statusCode,headers:response.headers,body:response}); + }); + request.setTimeout(30000,()=>request.destroy(new Error('Testing update network timeout.'))); + request.on('error',reject); + }); +} +async function responseFor(transport,url,kind){ + approvedURL(url,kind); + const response=await transport(url,{kind}); + if(response.statusCode!==200){response.body?.destroy?.();throw new Error('Release server did not return an asset.');} + return response; +} +async function jsonAt(transport,url,kind='asset'){ + const response=await responseFor(transport,url,kind),chunks=[];let size=0; + for await(const chunk of response.body){size+=chunk.length;if(size>1024*1024){response.body.destroy?.();throw new Error('Release metadata exceeds bounds.');}chunks.push(chunk);} + if(response.headers?.['content-length']&&Number(response.headers['content-length'])!==size)throw new Error('Release metadata truncated.'); + return JSON.parse(Buffer.concat(chunks).toString('utf8')); +} +function assetURL(asset,tag,name){ + const expected=`https://github.com/${REPOSITORY}/releases/download/${encodeURIComponent(tag)}/${encodeURIComponent(name)}`; + if(!asset||asset.name!==name||asset.browser_download_url!==expected)throw new Error('Release asset is not in the official repository.'); + approvedURL(expected,'asset');return expected; +} +function createTestingUpdateCoordinator({app,manifest,distribution,publishStatus=()=>{},prepareQuit,authorizeQuit=()=>{},revokeQuit=()=>{},onInstallationFailure=()=>{},installedBundle,transport=httpsTransport,verifyCandidate=validateTestingCandidate,revalidateCandidate=revalidateTestingCandidate,installHelper,processIdentity,hostVersion,timers=globalThis,random=Math.random,enabled}){ + installedBundle||=path.resolve(app.getPath('exe'),'../../..'); + let status={state:'Current',installed:manifest.application_version,available:null,channel:'unsigned-testing',manual_updates:true,can_download:false,can_restart:false,developer_id_verified:false,message:'Using the installed testing version.'}; + let active=false,stopped=false,timer=null,checking=null,downloading=null,installing=null,pending=null,offered=null; + let receiptWrites=Promise.resolve(); + function set(state,fields={}){ + status={...status,...fields,state,can_download:state==='Available'&&Boolean(offered),can_restart:state==='Ready'&&Boolean(pending)};publishStatus({...status}); + const snapshot={format:'rieke-desktop-testing-update-status',version:1,installed:status.installed,available:status.available,state,checked_at:status.checked_at||null}; + receiptWrites=receiptWrites.catch(()=>{}).then(async()=>{ + const cache=await ensurePrivateCache(app.getPath('userData')); + const temporary=path.join(cache,`status-${crypto.randomUUID()}.tmp`); + await fs.writeFile(temporary,JSON.stringify(snapshot)+'\n',{mode:0o600,flag:'wx'}); + await fs.rename(temporary,path.join(cache,'status.json')); + }).catch(()=>{}); + return {...status}; + } + function deferred(message){return set(pending?'Ready':offered?'Available':'Deferred',{message,check_error:message});} + async function forgetHint(){try{const cache=await ensurePrivateCache(app.getPath('userData'));await fs.rm(path.join(cache,'prepared.json'),{force:true});}catch{}} + async function persistPrepared(cache,candidate,descriptor){ + const hint={format:'rieke-desktop-testing-prepared-hint',version:1,installed_version:manifest.application_version, + available_version:candidate.version,archive_relative_path:path.relative(cache,candidate.downloadedFile).split(path.sep).join('/'), + bundle_relative_path:path.relative(cache,candidate.bundle_path).split(path.sep).join('/'), + archive_sha256:descriptor.archive.sha256,bundle_sha256:candidate.bundle_sha256,runtime_manifest_sha256:descriptor.runtime_manifest_sha256}; + await hintPath(cache,hint.archive_relative_path,'download',descriptor.archive.filename); + await hintPath(cache,hint.bundle_relative_path,'candidate','Rieke OS.app'); + await atomicHint(cache,hint); + } + async function resumePrepared(selected){ + const cache=await ensurePrivateCache(app.getPath('userData')),file=path.join(cache,'prepared.json'); + let candidate=null; + try{ + const handle=await fs.open(file,constants.O_RDONLY|constants.O_NOFOLLOW); + let hint; + try{const stat=await handle.stat();if(!stat.isFile()||stat.uid!==process.getuid()||(stat.mode&0o077)||stat.size>65536)throw new Error('Invalid prepared hint ownership.');hint=JSON.parse(await handle.readFile('utf8'));}finally{await handle.close();} + const descriptor=selected.descriptor; + if(hint.format!=='rieke-desktop-testing-prepared-hint'||hint.version!==1||hint.installed_version!==manifest.application_version||hint.available_version!==descriptor.application_version||hint.archive_sha256!==descriptor.archive.sha256||hint.runtime_manifest_sha256!==descriptor.runtime_manifest_sha256||!/^[a-f0-9]{64}$/.test(hint.bundle_sha256||''))throw new Error('Prepared hint differs from fresh official metadata.'); + const downloadedFile=await hintPath(cache,hint.archive_relative_path,'download',descriptor.archive.filename); + const bundle=await hintPath(cache,hint.bundle_relative_path,'candidate','Rieke OS.app'); + candidate={version:descriptor.application_version,downloadedFile,bundle_path:bundle,bundle_sha256:hint.bundle_sha256, + archive_sha256:descriptor.archive.sha256,runtime_manifest_sha256:descriptor.runtime_manifest_sha256,validated:true,descriptor,candidate_directory:path.dirname(bundle)}; + set('Validating',{message:'Rechecking the previously downloaded testing update against current GitHub metadata.'}); + await verifyArchive(downloadedFile,descriptor); + const checked=await revalidateCandidate({candidate,descriptor,manifest,hostVersion}); + if(stopped)throw new Error('Updater stopped.'); + pending={...candidate,source_dirty:checked?.source_dirty}; + set('Ready',{source_dirty:pending.source_dirty,trust:'official-repository-https-checksums',developer_id_verified:false,message:'Previously downloaded unsigned testing update verified again. Restart to update when ready.'}); + await cleanupObsolete(cache,[path.dirname(downloadedFile),path.dirname(bundle)]).catch(()=>{}); + return true; + }catch{if(!stopped)await forgetHint();return false;} + } + function schedule(){ + if(stopped||!active)return; + timer=timers.setTimeout(async()=>{await check();schedule();},Math.round(3600000*(0.9+random()*0.2)));timer?.unref?.(); + } + async function check(){ + if(!active||stopped||pending||downloading||installing)return {...status}; + if(checking)return checking; + checking=(async()=>{ + set('Checking',{checked_at:new Date().toISOString(),check_error:null,message:'Checking the official GitHub testing releases.'}); + try{ + const releases=await jsonAt(transport,API,'api'); + if(!Array.isArray(releases)||releases.length>100)throw new Error('Invalid testing release list.'); + const relevant=releases.filter(release=>{ + if(release?.draft||typeof release.tag_name!=='string')return false; + const match=/^(?:v|desktop-test-v)(\d+\.\d+\.\d+)$/.exec(release.tag_name); + try{return match&&compareVersions(match[1],manifest.application_version)>0;}catch{return false;} + }).sort((a,b)=>compareVersions(b.tag_name.replace(/^(?:v|desktop-test-v)/,''),a.tag_name.replace(/^(?:v|desktop-test-v)/,''))); + let candidate=null,rejections=0; + for(const release of relevant.slice(0,20)){ + const assets=release.assets; + if(!Array.isArray(assets))continue; + const descriptors=assets.filter(asset=>asset?.name==='desktop-release.json'); + if(descriptors.length!==1)continue; + try{ + const descriptor=validateDescriptor(await jsonAt(transport,assetURL(descriptors[0],release.tag_name,'desktop-release.json')),manifest,hostVersion); + if(release.tag_name!==`v${descriptor.application_version}`&&release.tag_name!==`desktop-test-v${descriptor.application_version}`)throw new Error('Release tag differs from app version.'); + const archives=assets.filter(asset=>asset?.name===descriptor.archive.filename); + if(archives.length!==1||archives[0].size!==descriptor.archive.size)throw new Error('Archive metadata differs from descriptor.'); + candidate={descriptor,url:assetURL(archives[0],release.tag_name,descriptor.archive.filename),release_url:`https://github.com/${REPOSITORY}/releases/tag/${encodeURIComponent(release.tag_name)}`};break; + }catch{rejections++;} + } + if(stopped)return {...status}; + if(candidate){ + offered=candidate;set('Available',{available:candidate.descriptor.application_version,release_url:candidate.release_url,source_dirty:null,message:`Rieke OS ${candidate.descriptor.application_version} testing update is available. Download when ready.`,check_error:null}); + if(!await resumePrepared(candidate)&&!stopped)set('Available',{message:'Testing update available. Download when ready; any missing or changed cached update will be replaced.'}); + } + else if(rejections)deferred('Published testing update metadata was rejected. The installed app remains usable.'); + else{offered=null;set('Current',{available:null,message:'The installed testing version is current.',check_error:null});} + }catch{deferred('Testing update check unavailable. The installed app remains usable.');} + return {...status}; + })().finally(()=>{checking=null;});return checking; + } + async function start(){ + if(active||stopped)return {...status}; + if(enabled===false||!app.isPackaged||process.platform!=='darwin'||process.arch!=='arm64'||distribution?.format!=='rieke-desktop-distribution'||distribution.version!==1||distribution.channel!=='unsigned-testing'||distribution.repository!==REPOSITORY)return set('Deferred',{message:'This distribution does not enable GitHub testing updates.'}); + try{ + hostVersion||=(await runFile('/usr/bin/sw_vers',['-productVersion'])).stdout.trim(); + const cache=await ensurePrivateCache(app.getPath('userData')); + // Disk status is a display hint, never authority to install or restore. + try{const hint=JSON.parse(await fs.readFile(path.join(cache,'status.json'),'utf8'));if(hint.format==='rieke-desktop-testing-update-status'&&hint.installed===manifest.application_version)status.available=hint.available;}catch{} + }catch{return set('Deferred',{message:'The testing update cache is unavailable.'});} + active=true;await check();schedule();return {...status}; + } + async function download(){ + if(!active||stopped)return {...status}; + if(downloading)return downloading; + if(installing||pending)return {...status}; + if(checking)await checking; + if(pending)return {...status}; + if(!offered)return {...status}; + const selected=offered; + downloading=(async()=>{ + let directory=null,candidate=null; + try{ + set('Downloading',{progress:0,check_error:null,message:'Downloading the selected unsigned testing update.'}); + const cache=await ensurePrivateCache(app.getPath('userData')); + directory=await fs.mkdtemp(path.join(cache,'download-')); + const file=path.join(directory,selected.descriptor.archive.filename); + const response=await responseFor(transport,selected.url,'asset'); + if(response.headers?.['content-length']&&Number(response.headers['content-length'])!==selected.descriptor.archive.size){response.body.destroy?.();throw new Error('Archive length differs.');} + const output=await fs.open(file,constants.O_WRONLY|constants.O_CREAT|constants.O_EXCL|constants.O_NOFOLLOW,0o600); + let size=0,lastPercent=-1,lastPublished=0; + try{ + for await(const chunk of response.body){ + size+=chunk.length;if(stopped||size>selected.descriptor.archive.size){response.body.destroy?.();throw new Error('Archive download interrupted or oversized.');} + await output.writeFile(chunk); + const percent=Math.min(100,Math.floor(100*size/selected.descriptor.archive.size)),now=Date.now(); + if(percent!==lastPercent||now-lastPublished>=200){set('Downloading',{progress:percent});lastPercent=percent;lastPublished=now;} + } + await output.sync(); + }finally{await output.close();} + await verifyArchive(file,selected.descriptor); + set('Validating',{progress:100,message:'Checking the testing app checksums and data compatibility.'}); + candidate=await verifyCandidate({downloadedFile:file,descriptor:selected.descriptor,manifest,cacheDirectory:cache,installedBundle,hostVersion}); + if(stopped)throw new Error('Updater stopped.'); + await persistPrepared(cache,candidate,selected.descriptor); + pending={...candidate,descriptor:selected.descriptor}; + set('Ready',{available:candidate.version,source_dirty:candidate.source_dirty,trust:'official-repository-https-checksums',developer_id_verified:false,message:'Unsigned testing update verified. Restart to update when your work is saved.'}); + await cleanupObsolete(cache,[directory,candidate.candidate_directory||path.dirname(candidate.bundle_path)]).catch(()=>{}); + }catch{ + if(candidate?.candidate_directory)await fs.rm(candidate.candidate_directory,{recursive:true,force:true}); + if(directory)await fs.rm(directory,{recursive:true,force:true}); + pending=null;await forgetHint();deferred('Testing update download or validation failed. You can retry the download.'); + } + return {...status}; + })().finally(()=>{downloading=null;});return downloading; + } + async function verifyPrepared(){ + await ensurePrivateCache(app.getPath('userData')); + await verifyArchive(pending.downloadedFile,pending.descriptor); + await revalidateCandidate({candidate:pending,descriptor:pending.descriptor,manifest,hostVersion}); + } + async function installPrepared(){ + if(installing)return installing; + if(downloading)await downloading; + if(!active||stopped||!pending||status.state!=='Ready')return{ready:false,reason:'No verified testing update is prepared.'}; + installing=(async()=>{ + let drained=false; + try{ + await verifyPrepared();set('Draining',{message:'Saving drafts and closing scientific services before updating.'}); + const result=await prepareQuit(); + if(result?.ready!==true){set('Ready',{message:'Testing update remains pending until drafts, writers and services close.'});return{ready:false,reason:result?.reason||status.message};} + drained=true;await verifyPrepared();if(stopped)throw new Error('Updater stopped during drain.'); + const helper=(!processIdentity||!installHelper)?require('./testing-install.cjs'):{}; + const identity=await (processIdentity||helper.processCreationIdentity)(process.pid,app.getPath('exe')); + const cache=await ensurePrivateCache(app.getPath('userData')); + const receiptPath=path.join(cache,`install-${crypto.randomUUID()}.json`); + const receipt={format:'rieke-unsigned-testing-update',version:1,channel:'unsigned-testing',identifier:'org.riekeos.desktop',operation:'update',install_path:installedBundle,current_executable:typeof identity==='object'?identity.executable:app.getPath('exe'),current_pid:process.pid,current_created_at:typeof identity==='object'?identity.created_at:identity,current_version:manifest.application_version,current_manifest_sha256:await hashFile(path.join(installedBundle,'Contents/Resources/runtime/runtime-manifest.json')),target_version:pending.version,runtime_manifest_sha256:pending.runtime_manifest_sha256,archive_path:pending.downloadedFile,archive_sha256:pending.archive_sha256,bundle_path:pending.bundle_path,bundle_sha256:pending.bundle_sha256,validated:true}; + // Version is separately named because receipt.version identifies schema. + await fs.writeFile(receiptPath,JSON.stringify(receipt)+'\n',{mode:0o600,flag:'wx'}); + set('Installing',{message:'Handing the verified unsigned testing app to the owned installer.'}); + const handoff=await (installHelper||helper.launchTestingInstall)({receiptPath,currentExecutable:receipt.current_executable,currentPid:process.pid}); + if(handoff?.ready===false)throw new Error('Testing installer did not acknowledge readiness.'); + authorizeQuit();app.quit?.();return{ready:true,installing:true}; + }catch{ + revokeQuit();pending=null;await forgetHint();deferred(drained?'Testing update changed or installation failed. Restart the installed app from recovery.':'The prepared testing update changed or is unavailable. Retry the download; the installed app remains usable.'); + if(drained)onInstallationFailure();return{ready:false,reason:status.message}; + } + })().finally(()=>{installing=null;});return installing; + } + function stop(){stopped=true;active=false;if(timer)timers.clearTimeout(timer);} + return{getStatus:()=>({...status}),start,check,download,installPrepared,stop,flushReceipts:()=>receiptWrites}; +} +module.exports={createTestingUpdateCoordinator,httpsTransport}; diff --git a/desktop/tests/bootstrap.test.cjs b/desktop/tests/bootstrap.test.cjs new file mode 100644 index 0000000..0cd43b3 --- /dev/null +++ b/desktop/tests/bootstrap.test.cjs @@ -0,0 +1,23 @@ +'use strict'; +const {test} = require('node:test'); +const assert = require('node:assert/strict'); +const {signatureIdentity, assertNotRunning, compatibleManifest, enclosingApp, installCompleteBundle} = require('../bootstrap.cjs'); +test('bootstrap accepts only complete Developer ID signed app with exact identity', async () => { + const run = async (_command, args) => ({stdout: '', stderr: args.includes('--display') ? 'Identifier=org.riekeos.desktop\nTeamIdentifier=EXAMPLETEAM\nAuthority=Developer ID Application: Example\n' : ''}); + assert.deepEqual(await signatureIdentity('/tmp/Rieke OS.app', run), {identifier: 'org.riekeos.desktop', team: 'EXAMPLETEAM'}); + await assert.rejects(signatureIdentity('/tmp/Rieke OS.app', async () => ({stdout: '', stderr: 'Identifier=org.riekeos.desktop\nTeamIdentifier=not set\nSignature=adhoc'})), /Developer ID/); +}); +test('any installed app process blocks replacement and only dedicated helper PID is exempt', async () => { + const run = async () => ({stdout: ` ${process.pid} /tmp/Rieke OS.app/Contents/MacOS/Rieke OS\n 100 /usr/bin/other\n`}); + await assert.rejects(assertNotRunning('/tmp/Rieke OS.app', run), /running/); + await assertNotRunning('/tmp/Rieke OS.app', run, process.pid); + await assert.rejects(installCompleteBundle({source: '/tmp/source.app', allowRollback: false, ignorePid: process.pid}), /dedicated/); +}); +test('bootstrap refuses MySQL or workspace compatibility changes even in signed apps', () => { + const current = {format: 'rieke-desktop-runtime', version: 1, platform: 'darwin', architecture: 'arm64', mysql_version: '8.4.2', workspace_formats: [1], database_compatibility: 1}; + assert.equal(compatibleManifest(current, current), true); + assert.equal(compatibleManifest({...current, mysql_version: '9.0.0'}, current), false); + assert.equal(compatibleManifest({...current, workspace_formats: [2]}, current), false); + assert.equal(compatibleManifest({...current, database_compatibility: 2}, current), false); + assert.equal(enclosingApp('/Applications/Rieke OS.app/Contents/MacOS/Rieke OS'), '/Applications/Rieke OS.app'); +}); diff --git a/desktop/tests/distribution.test.cjs b/desktop/tests/distribution.test.cjs new file mode 100644 index 0000000..40a768b --- /dev/null +++ b/desktop/tests/distribution.test.cjs @@ -0,0 +1,11 @@ +'use strict'; +const test = require('node:test'); +const assert = require('node:assert/strict'); +const {distributionPolicy} = require('../distribution.cjs'); +test('normal installs retain signed update policy unless an explicit testing build opts in', () => { + assert.equal(distributionPolicy().channel, 'signed'); + assert.equal(distributionPolicy({format:'rieke-desktop-distribution',version:1,channel:'unsigned-testing',repository:'maxwellsdm1867/Rieke-OS'}).channel,'unsigned-testing'); +}); +test('a testing build cannot redirect users to a foreign repository or unknown trust channel', () => { + for(const value of [{format:'rieke-desktop-distribution',version:1,channel:'unsigned-testing',repository:'someone/other'}, {format:'rieke-desktop-distribution',version:1,channel:'anything',repository:'maxwellsdm1867/Rieke-OS'}]) assert.throws(()=>distributionPolicy(value)); +}); diff --git a/desktop/tests/draft-barrier.test.cjs b/desktop/tests/draft-barrier.test.cjs new file mode 100644 index 0000000..36bdf53 --- /dev/null +++ b/desktop/tests/draft-barrier.test.cjs @@ -0,0 +1,20 @@ +'use strict'; +const {test} = require('node:test'); +const assert = require('node:assert/strict'); +const {DraftBarrier} = require('../draft-barrier.cjs'); +const window = () => ({isDestroyed: () => false}); +test('every scientific window must acknowledge its own persisted draft before drain', async () => { + const requests = []; const barrier = new DraftBarrier({timeout: 50, send: (win, request) => requests.push({win, ...request})}); + const a = window(), b = window(); const result = barrier.prepare([a, b]); + assert.throws(() => barrier.acknowledge({requestId: requests[0].requestId, ok: true}, b)); + barrier.acknowledge({requestId: requests[0].requestId, ok: true}, a); + barrier.acknowledge({requestId: requests[1].requestId, ok: true}, b); + assert.deepEqual(await result, {ready: true}); + assert.equal(barrier.pending.size, 0); +}); +test('missing, failed and crashed renderer acknowledgements defer quit', async () => { + const barrier = new DraftBarrier({timeout: 5, send: () => {}}); + assert.equal((await barrier.prepare([window()])).ready, false); + assert.equal((await barrier.prepare([{isDestroyed: () => false, draftUnavailable: true}])).ready, false); + assert.equal((await barrier.prepare([{isDestroyed: () => true}])).ready, false); +}); diff --git a/desktop/tests/draft-store.test.cjs b/desktop/tests/draft-store.test.cjs new file mode 100644 index 0000000..ba460d9 --- /dev/null +++ b/desktop/tests/draft-store.test.cjs @@ -0,0 +1,30 @@ +'use strict'; +const {test} = require('node:test'); const assert = require('node:assert/strict'); +const fs = require('node:fs/promises'), path = require('node:path'), os = require('node:os'); +const {DraftStore, MAX_DRAFT_BYTES} = require('../draft-store.cjs'); +const payload = () => ({projectId: 'launcher', value: {format: 'rieke-renderer-draft', version: 1, projectId: 'launcher', value: {route: {page: 'overview'}}}}); +async function fixture(t) {const root = await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-drafts-')); t.after(() => fs.rm(root, {recursive: true, force: true})); const store = new DraftStore(root); await store.location('launcher'); return {root, store, filename: path.join(root, 'drafts/launcher.json')};} +test('missing drafts are ordinary and valid durable schema roundtrips', async t => { + const {store} = await fixture(t); assert.equal(await store.load('launcher'), null); + await store.save(payload()); assert.deepEqual(await store.load('launcher'), payload().value); + await assert.rejects(store.reset('launcher'), /No verified/); + await assert.rejects(store.save({projectId: 'launcher', value: {route: 'files'}}), /schema/); +}); +test('malformed, mismatched and oversized stored drafts block overwrite until explicit preserved reset', async t => { + const {store, filename, root} = await fixture(t); + for (const bytes of ['{corrupted', JSON.stringify({...payload().value, projectId: 'foreign'}), 'x'.repeat(MAX_DRAFT_BYTES + 1)]) { + await fs.writeFile(filename, bytes); + assert.equal((await store.load('launcher')).format, 'rieke-draft-recovery'); + await assert.rejects(store.save(payload()), /recovery decision/); assert.equal(await fs.readFile(filename, 'utf8'), bytes); + await store.reset('launcher'); assert.equal(await store.load('launcher'), null); + const backups = (await fs.readdir(path.join(root, 'drafts'))).filter(name => name.startsWith('launcher.corrupt-')); + assert.ok((await Promise.all(backups.map(name => fs.readFile(path.join(root, 'drafts', name), 'utf8')))).includes(bytes)); + } +}); +test('symlink draft never reads target and reset preserves link without changing target', async t => { + const {store, filename, root} = await fixture(t); const target = path.join(root, 'private-target'); await fs.writeFile(target, 'keep target'); await fs.symlink(target, filename); + assert.equal((await store.load('launcher')).format, 'rieke-draft-recovery'); await assert.rejects(store.save(payload())); + await store.reset('launcher'); assert.equal(await fs.readFile(target, 'utf8'), 'keep target'); + const backup = (await fs.readdir(path.join(root, 'drafts'))).find(name => name.startsWith('launcher.corrupt-')); + assert.equal((await fs.lstat(path.join(root, 'drafts', backup))).isSymbolicLink(), true); +}); diff --git a/desktop/tests/e2e/updater-client.cjs b/desktop/tests/e2e/updater-client.cjs new file mode 100644 index 0000000..5e4b2c0 --- /dev/null +++ b/desktop/tests/e2e/updater-client.cjs @@ -0,0 +1,119 @@ +'use strict'; +// Run with the pinned Electron executable. This exercises its real HTTP +// executor, pinned MacUpdater parser/downloader and app coordinator against a +// private fault server. It does not substitute for a signed Squirrel update. +const {app, autoUpdater: nativeUpdater} = require('electron'); +const fs = require('node:fs/promises'); +const path = require('node:path'); +const os = require('node:os'); +const http = require('node:http'); +const crypto = require('node:crypto'); +const assert = require('node:assert/strict'); +const {MacUpdater} = require('electron-updater'); +const {ElectronHttpExecutor} = require('electron-updater/out/electronHttpExecutor'); +const {createUpdateCoordinator} = require('../../updater.cjs'); +const root = path.resolve(__dirname, '../../..'); +const payload = Buffer.alloc(256 * 1024, 23); +const unhandled = []; +process.on('unhandledRejection', error => unhandled.push(error.code || error.name || 'unknown')); +const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); +async function eventually(predicate, timeout = 10000) { + const deadline=Date.now()+timeout; + while(Date.now(){ + requests++; + if(request.url.includes('latest-mac.yml')){ + if(fault==='metadata-unavailable'){response.writeHead(503);response.end('unavailable');return;} + response.setHeader('Content-Type','application/yaml'); + response.end(fault==='malformed-metadata'?'files: [invalid':JSON.stringify(metadata));return; + } + downloads++; + response.writeHead(200,{'Content-Type':'application/zip','Content-Length':payload.length}); + if(fault==='interrupted-download'||(fault==='interrupted-download-fresh-client'&&downloads===1)){response.write(payload.subarray(0,1024));setTimeout(()=>response.destroy(),25);} + else response.end(payload); + }); + await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve)); + const feed=`http://127.0.0.1:${server.address().port}/`; + const adapter={version:'0.1.0',name:'Rieke updater isolated E2E',isPackaged:true,appUpdateConfigPath:configuration,userDataPath:dir,baseCachePath:dir, + whenReady:()=>app.whenReady(),onQuit:()=>{},quit:()=>assert.fail('Client cannot quit app in rejected scenarios'),relaunch:()=>assert.fail('Client cannot relaunch app')}; + let updater; + const states=[]; + function createClient(){ + updater=new MacUpdater(undefined,adapter); + updater.httpExecutor=new ElectronHttpExecutor(()=>{}); + updater.logger=null; + updater.disableDifferentialDownload=true; + const setFeed=updater.setFeedURL.bind(updater); + // Substitute only the delivery destination. The production provider arguments + // are asserted and every HTTP/metadata/cache operation remains real. + updater.setFeedURL=provider=>{ + assert.equal(provider.provider,'github');assert.equal(provider.owner,'maxwellsdm1867');assert.equal(provider.repo,'Rieke-OS'); + setFeed({provider:'generic',url:feed}); + }; + updater.quitAndInstall=()=>{installs++;assert.fail('Rejected update cannot install');}; + return createUpdateCoordinator({app:{isPackaged:true,getPath:()=>dir},manifest:{application_version:'0.1.0'},updater, + verifyInstalled:async()=>({fixture_only:true}), + // The candidate's real production verifier cannot accept an unsigned test + // bundle. Transport success must end rejected, with no native installer. + verifyCandidate:async()=>{throw new Error('No Developer ID test candidate');},retainPrevious:async()=>assert.fail('Rejected candidate cannot retain/activate'), + prepareQuit:async()=>assert.fail('Rejected candidate cannot drain app'),publishStatus:status=>states.push(status.state), + timers:{setTimeout:()=>1,clearTimeout:()=>{}}}); + } + const nativeListeners=new Map(['error','update-downloaded'].map(name=>[name,nativeUpdater.listeners(name)])); + let coordinator=createClient(); + const initialUnhandled=unhandled.length; + try{ + await coordinator.start(); + if(['bad-checksum','interrupted-download','interrupted-download-fresh-client','unsigned-candidate','cache-write-failure'].includes(fault))await eventually(()=>states.includes('Deferred')); + await wait(100); + if(fault==='interrupted-download-fresh-client'){ + assert.equal(downloads,1);assert.equal(coordinator.getStatus().state,'Deferred'); + coordinator.stop();updater.closeServerIfExists();states.length=0; + coordinator=createClient();await coordinator.start(); + await eventually(()=>states.includes('Deferred'));await wait(100); + assert.equal(downloads,2,'A fresh real client must fetch complete bytes instead of using the interrupted cache'); + assert.equal(adapter.version,'0.1.0'); + } + const final=coordinator.getStatus().state; + assert.equal(final,['older-version','current-version'].includes(fault)?'Current':'Deferred'); + assert.equal(installs,0); + assert.equal(updater.autoInstallOnAppQuit,false); + assert.equal(unhandled.length,initialUnhandled,`Unhandled real downloader rejection for ${fault}`); + if(['older-version','current-version','invalid-version','malformed-metadata','metadata-unavailable','cache-write-failure'].includes(fault))assert.equal(downloads,0); + report.scenarios.push({name:fault,passed:true,requests,downloads,final_state:final,native_installs:installs}); + }finally{ + coordinator.stop();updater.closeServerIfExists(); + await new Promise(resolve=>server.close(resolve)); + for(const [event,listeners] of nativeListeners)for(const listener of listeners)nativeUpdater.removeListener(event,listener); + } +} +async function main(){ + const base=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-updater-client-e2e-')); + await fs.mkdir(path.join(base,'electron-profile')); + app.setPath('userData',path.join(base,'electron-profile')); + await app.whenReady(); + const report={format:'rieke-updater-client-e2e',version:1,production_ready:false,library_version:require('electron-updater/package.json').version, + scenarios:[],limitations:['Private fixture provider and test app identity; no Developer ID candidate','Real signed Squirrel staging/install/recovery remains unqualified']}; + try{ + for(const fault of ['current-version','older-version','metadata-unavailable','malformed-metadata','invalid-version','bad-checksum','interrupted-download','interrupted-download-fresh-client','cache-write-failure','unsigned-candidate'])await scenario(base,fault,report); + report.passed=true; + }catch(error){report.passed=false;report.failure=error.message;process.exitCode=1;} + report.unhandled_rejections=unhandled; + await fs.writeFile(path.join(root,'docs/dev/desktop-updater-client-e2e.json'),JSON.stringify(report,null,2)+'\n'); + console.log(JSON.stringify(report,null,2)); + app.exit(report.passed?0:1); +} +main().catch(error=>{console.error(error.name+': '+error.message);app.exit(1);}); diff --git a/desktop/tests/physical-fs.test.cjs b/desktop/tests/physical-fs.test.cjs new file mode 100644 index 0000000..d3e47b0 --- /dev/null +++ b/desktop/tests/physical-fs.test.cjs @@ -0,0 +1,40 @@ +'use strict'; +const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs/promises'),path=require('node:path'),os=require('node:os'),crypto=require('node:crypto'); +const {promisify}=require('node:util'),run=promisify(require('node:child_process').execFile); +const asar=require('@electron/asar'); +test('actual Electron validates physical ASAR bytes and removes its cache without virtual-directory traversal',async t=>{ + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-physical-asar-'));t.after(()=>fs.rm(root,{recursive:true,force:true})); + const content=path.join(root,'content'),cache=path.join(root,'candidate'),archive=path.join(cache,'app.asar'); + await fs.mkdir(content);await fs.mkdir(cache);await fs.writeFile(path.join(content,'package.json'),JSON.stringify({name:'asar-boundary-fixture',version:'1.0.0'}));await fs.writeFile(path.join(content,'payload.txt'),'physical archive byte proof'); + await asar.createPackage(content,archive);const expected=crypto.createHash('sha256').update(await fs.readFile(archive)).digest('hex'); + const driver=path.join(root,'driver.cjs'); + await fs.writeFile(driver,`const assert=require('node:assert/strict'),virtual=require('node:fs'),path=require('node:path'); +const physical=require(process.argv[2]),{hashFile}=require(process.argv[3]); +(async()=>{const archive=process.argv[4];assert.equal(virtual.lstatSync(archive).isDirectory(),true);assert.equal(physical.lstatSync(archive).isFile(),true);assert.equal(await hashFile(archive),process.argv[5]);await physical.promises.rm(path.dirname(archive),{recursive:true});console.log('RIEKE_PHYSICAL_ASAR_PASS');})().catch(error=>{console.error(error.stack);process.exitCode=1;});`); + const result=await run(require('electron'),[driver,path.resolve(__dirname,'../physical-fs.cjs'),path.resolve(__dirname,'../testing-update-validation.cjs'),archive,expected],{timeout:30000,env:{...process.env,ELECTRON_RUN_AS_NODE:'1',HOME:root,PATH:'/usr/bin:/bin'}}); + assert.match(result.stdout,/RIEKE_PHYSICAL_ASAR_PASS/);await assert.rejects(fs.access(cache)); +}); +test('actual Electron signed candidate rejection cleans extracted ASAR while retaining Developer ID policy',{skip:process.platform!=='darwin'},async t=>{ + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-signed-asar-reject-'));t.after(()=>fs.rm(root,{recursive:true,force:true})); + const content=path.join(root,'content'),bundle=path.join(root,'Rieke OS.app'),resources=path.join(bundle,'Contents/Resources');await fs.mkdir(content);await fs.mkdir(resources,{recursive:true}); + await fs.writeFile(path.join(content,'never-execute.cjs'),'throw new Error("candidate executed")');await asar.createPackage(content,path.join(resources,'app.asar')); + const installed=path.join(root,'Installed.app'),bin=path.join(installed,'Contents/Resources/runtime/python/bin');await fs.mkdir(bin,{recursive:true}); + let python=path.resolve(__dirname,'../build/runtime/python/bin/python3.11');try{await fs.access(python);}catch{python=(await run('/usr/bin/which',['python3'])).stdout.trim();} + await fs.symlink(python,path.join(bin,'python3.11')); + const archive=path.join(root,'candidate.zip');await run(python,['-I','-B','-c',String.raw`import sys,zipfile +from pathlib import Path +root=Path(sys.argv[1]) +with zipfile.ZipFile(sys.argv[2],'w') as z: + for file in root.rglob('*'): + if file.is_file():z.write(file,str(file.relative_to(root.parent)))`,bundle,archive]); + const driver=path.join(root,'driver.cjs'); + await fs.writeFile(driver,`const assert=require('node:assert/strict'),path=require('node:path'),fs=require('original-fs').promises,{promisify}=require('node:util'); +const realRun=promisify(require('node:child_process').execFile),{validateDownloadedCandidate}=require(process.argv[2]); +const installed=process.argv[3],cache=path.join(process.argv[5],'cache'); +let extracted=false; +(async()=>{await assert.rejects(validateDownloadedCandidate({downloadedFile:process.argv[4],version:'1.1.0',manifest:{application_version:'1.0.0'},cacheDirectory:cache,installedBundle:installed, + run:async(exe,args,options)=>{if(exe==='/usr/bin/codesign'){if(args.at(-1)!==installed){extracted=true;throw new Error('untrusted candidate signer');}return {stdout:'',stderr:'TeamIdentifier=TESTTEAM\\nIdentifier=org.riekeos.desktop\\nAuthority=Developer ID Application: simulated current signature for cleanup boundary'};}return realRun(exe,args,options);}}),/untrusted candidate signer/); +assert.equal(extracted,true);assert.deepEqual(await fs.readdir(cache),[]);console.log('RIEKE_SIGNED_ASAR_REJECT_CLEAN');})().catch(error=>{console.error(error.stack);process.exitCode=1;});`); + const result=await run(require('electron'),[driver,path.resolve(__dirname,'../updater-validation.cjs'),installed,archive,root],{timeout:30000,env:{...process.env,ELECTRON_RUN_AS_NODE:'1',HOME:root,PATH:'/usr/bin:/bin'}}); + assert.match(result.stdout,/RIEKE_SIGNED_ASAR_REJECT_CLEAN/); +}); diff --git a/desktop/tests/recovery-ui.test.cjs b/desktop/tests/recovery-ui.test.cjs new file mode 100644 index 0000000..e7e6aa1 --- /dev/null +++ b/desktop/tests/recovery-ui.test.cjs @@ -0,0 +1,20 @@ +'use strict'; +const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'),path=require('node:path'),vm=require('node:vm'); +function page(initial){ + const elements=new Map(),element=id=>{if(!elements.has(id))elements.set(id,{hidden:false,disabled:false,textContent:''});return elements.get(id);};let listener,installs=0; + const bridge={status:async()=>initial,onStatus:fn=>{listener=fn;},installAndOpen:async()=>{installs++;return {ready:false,reason:'Another installed app is still running.'};},retryStartup:async()=>{},restorePreviousVersion:async()=>{},quit:async()=>{}}; + vm.runInNewContext(fs.readFileSync(path.join(__dirname,'../recovery.js'),'utf8'),{window:{riekeDesktop:bridge},document:{getElementById:element}}); + return {element,get installs(){return installs;},emit:status=>listener(status),settle:()=>new Promise(resolve=>setImmediate(resolve)),click:async id=>element(id).onclick({target:element(id)})}; +} +test('unsigned bootstrap explains Open Anyway only before installation and requires an explicit Install and Open',async()=>{ + const h=page({state:'Bootstrap',channel:'unsigned-testing',title:'Install Rieke OS',message:'Install this complete app in your Applications folder and open it.'});await h.settle(); + assert.equal(h.element('channel').hidden,false);assert.match(h.element('channel').textContent,/Unsigned testing/); + assert.equal(h.element('gatekeeper').hidden,false);assert.match(h.element('gatekeeper').textContent,/Open Anyway/); + assert.equal(h.installs,0);await h.click('install');assert.equal(h.installs,1);assert.match(h.element('detail').textContent,/still running/); + h.emit({state:'Recovery',channel:'unsigned-testing'});assert.equal(h.element('install').hidden,true);assert.equal(h.element('gatekeeper').hidden,true); +}); +test('signed bootstrap retains its signature guidance and never claims an unsigned exception',async()=>{ + const h=page({state:'Bootstrap',channel:'signed',detail:'Developer ID signature verification is required.'});await h.settle(); + assert.equal(h.element('channel').hidden,true);assert.equal(h.element('gatekeeper').hidden,true); + assert.equal(h.element('detail').textContent,'Developer ID signature verification is required.');assert.equal(h.installs,0); +}); diff --git a/desktop/tests/security.test.cjs b/desktop/tests/security.test.cjs new file mode 100644 index 0000000..8dcd952 --- /dev/null +++ b/desktop/tests/security.test.cjs @@ -0,0 +1,27 @@ +'use strict'; +const {test} = require('node:test'); +const assert = require('node:assert/strict'); +const {isOwnedURL, validateSender, validateDraft, approvedReleaseURL} = require('../security.cjs'); +test('only exact authenticated loopback origins and explicit recovery document are trusted', () => { + const origins = new Set(['http://127.0.0.1:1234']); + assert.equal(isOwnedURL('http://127.0.0.1:1234/api/project', origins), true); + for (const url of ['http://localhost:1234/', 'http://127.0.0.1:1235/', 'https://127.0.0.1:1234/', 'javascript:alert(1)', 'file:///tmp/foreign.html']) assert.equal(isOwnedURL(url, origins), false); + assert.equal(isOwnedURL('file:///tmp/recovery.html', origins, ['/tmp/recovery.html']), true); +}); +test('privileged IPC rejects foreign renderer, subframe and origin', () => { + const mainFrame = {url: 'http://127.0.0.1:1234/'}; const contents = {mainFrame}; + const window = {isDestroyed: () => false, webContents: contents}; + assert.equal(validateSender({sender: contents, senderFrame: mainFrame}, new Set([window]), 'http://127.0.0.1:1234'), window); + assert.throws(() => validateSender({sender: {}, senderFrame: mainFrame}, [window], 'http://127.0.0.1:1234')); + assert.throws(() => validateSender({sender: contents, senderFrame: {...mainFrame}}, [window], 'http://127.0.0.1:1234')); + mainFrame.url = 'https://evil.example/'; + assert.throws(() => validateSender({sender: contents, senderFrame: mainFrame}, [window], 'http://127.0.0.1:1234')); +}); +test('drafts reject path traversal, unknown fields, missing JSON and oversize', () => { + assert.equal(validateDraft({projectId: 'launcher', value: {route: 'project'}}).projectId, 'launcher'); + for (const payload of [{projectId: '../../evil', value: {}}, {projectId: 'launcher', value: {}, path: '/tmp'}, {projectId: 'launcher', value: undefined}, {projectId: 'launcher', value: 'x'.repeat(2 * 1024 * 1024)}]) assert.throws(() => validateDraft(payload)); +}); +test('external URLs are restricted to canonical HTTPS release notes', () => { + assert.equal(approvedReleaseURL('https://github.com/maxwellsdm1867/Rieke-OS/releases/tag/v0.1.0'), true); + for (const url of ['http://github.com/maxwellsdm1867/Rieke-OS/releases', 'https://github.com.evil.example/maxwellsdm1867/Rieke-OS/releases', 'https://github.com/user/other/releases', 'https://user:pass@github.com/maxwellsdm1867/Rieke-OS/releases']) assert.equal(approvedReleaseURL(url), false); +}); diff --git a/desktop/tests/sign-runtime.test.cjs b/desktop/tests/sign-runtime.test.cjs new file mode 100644 index 0000000..787bf59 --- /dev/null +++ b/desktop/tests/sign-runtime.test.cjs @@ -0,0 +1,22 @@ +'use strict'; +const {test} = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs/promises'); +const path = require('node:path'); +const os = require('node:os'); +const {resealRuntimeManifest} = require('../sign-runtime.cjs'); +const {verifyResources} = require('../updater-validation.cjs'); +test('manifest reseal tracks signed native bytes and internal symlinks while excluding metadata', async t => { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-seal-')); t.after(() => fs.rm(root, {recursive: true, force: true})); + await fs.writeFile(path.join(root, 'runtime-manifest.json'), JSON.stringify({format: 'rieke-desktop-runtime'})); + await fs.writeFile(path.join(root, 'runtime-audit.json'), '{}'); + await fs.writeFile(path.join(root, 'binary'), 'final signed bytes', {mode: 0o755}); + await fs.symlink('binary', path.join(root, 'entry')); + const manifest = await resealRuntimeManifest(root); + assert.deepEqual(Object.keys(manifest.resources), ['binary', 'entry']); + assert.equal(manifest.resources.binary.executable, true); + assert.equal(manifest.resources.entry.symlink, 'binary'); + await verifyResources(root, manifest.resources); + await fs.writeFile(path.join(root, 'binary'), 'mutated after outer signing'); + await assert.rejects(verifyResources(root, manifest.resources)); +}); diff --git a/desktop/tests/supervisor.test.cjs b/desktop/tests/supervisor.test.cjs new file mode 100644 index 0000000..6ef2ac2 --- /dev/null +++ b/desktop/tests/supervisor.test.cjs @@ -0,0 +1,92 @@ +'use strict'; +const {test} = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs/promises'); +const os = require('node:os'); +const path = require('node:path'); +const {EventEmitter} = require('node:events'); +const {ServiceSupervisor} = require('../supervisor.cjs'); +async function fixture(t, request, {bind = true} = {}) { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'rieke-supervisor-test-')); t.after(() => fs.rm(root, {recursive: true, force: true})); + const runtime = path.join(root, 'runtime'); + await fs.mkdir(path.join(runtime, 'python', 'bin'), {recursive: true}); + await fs.mkdir(path.join(runtime, 'application', 'python'), {recursive: true}); + await fs.writeFile(path.join(runtime, 'python', 'bin', 'python3.11'), 'interpreter'); + await fs.writeFile(path.join(runtime, 'application', 'python', 'workspace_desktop.py'), 'entry'); + const manifest = {format: 'rieke-desktop-runtime', version: 1, platform: process.platform, architecture: process.arch, + application_version: '0.1.0', source_commit: 'test-source', workspace_formats: [1], database_compatibility: 1}; + await fs.writeFile(path.join(runtime, 'runtime-manifest.json'), JSON.stringify(manifest)); + const child = new EventEmitter(); child.pid = 123456789; child.stdout = new EventEmitter(); child.stdout.resume = () => {}; let spawned; + const supervisor = new ServiceSupervisor({resourcesPath: root, userData: path.join(root, 'state'), appVersion: '0.1.0', startupTimeout: 5, drainTimeout: 5, + spawnProcess: (...args) => { + spawned = args; + if (bind) process.nextTick(() => child.stdout.emit('data', Buffer.from('RIEKE_DESKTOP_BOUND=' + JSON.stringify({pid: child.pid, session_id: supervisor.sessionId, + port: Number(args[1][args[1].indexOf('--port') + 1]), application_version: '0.1.0', source_commit: 'test-source'}) + '\n'))); + return child; + }, request: (...args) => request(supervisor, child, ...args)}); + return {supervisor, child, manifest, root, spawned: () => spawned}; +} +const response = (value, ok = true, status = 200) => ({ok, status, json: async () => value}); +test('readiness validates owned process/release/session; launch never relies on PATH', async t => { + const {supervisor, spawned} = await fixture(t, sup => response({...sup.expectedHealth(), ready: true})); + assert.match(await supervisor.start(), /^http:\/\/127\.0\.0\.1:/); + const [executable, args, options] = spawned(); + assert.ok(executable.startsWith(await fs.realpath(supervisor.resourcesPath))); assert.equal(args[0], '-B'); + assert.equal(options.env.PATH, undefined); assert.equal(options.env.PYTHONDONTWRITEBYTECODE, '1'); + assert.notEqual(supervisor.rendererCapability, supervisor.capability); +}); +test('occupied port receives zero capability requests without private owned bind handshake', async t => { + let requests = 0; + const {supervisor, child} = await fixture(t, () => { requests++; return response({ready: true, pid: 99, session_id: 'foreign'}); }, {bind: false}); + let killed = false; child.kill = () => { killed = true; }; + await assert.rejects(supervisor.start(), /deadline/); assert.equal(supervisor.ready, false); assert.equal(killed, false); assert.equal(requests, 0); +}); +test('busy writer drain keeps backend alive and resumes it without kill', async t => { + const routes = []; + const {supervisor, child} = await fixture(t, (sup, _child, url) => { + routes.push(url); + if (url.endsWith('/drain')) return response({error: 'busy'}, false, 409); + return response({...sup.expectedHealth(), ready: true}); + }); + child.kill = () => assert.fail('writer must never be killed'); + await supervisor.start(); assert.equal((await supervisor.drain()).ready, false); + assert.equal(supervisor.exited, false); assert.ok(routes.some(route => route.endsWith('/resume'))); +}); +test('drain acknowledgement alone cannot authorize replacement until actual process exit', async t => { + const {supervisor, child} = await fixture(t, (sup, _child, url) => response(url.endsWith('/health') ? {...sup.expectedHealth(), ready: true} : {ready: true})); + await supervisor.start(); assert.equal((await supervisor.drain()).ready, false); + child.emit('exit', 0); assert.equal((await supervisor.drain()).ready, true); +}); +test('unexpected process crash is never interpreted as a service drain', async t => { + const {supervisor, child} = await fixture(t, sup => response({...sup.expectedHealth(), ready: true})); + await supervisor.start(); child.emit('exit', 1); + assert.equal((await supervisor.drain()).ready, false); +}); +test('incompatible manifest is rejected before executing any code', async t => { + const {supervisor, root, manifest, spawned} = await fixture(t, () => assert.fail('no request allowed')); + manifest.database_compatibility = 'invalid'; await fs.writeFile(path.join(root, 'runtime', 'runtime-manifest.json'), JSON.stringify(manifest)); + await assert.rejects(supervisor.start(), /compatibility/); assert.equal(spawned(), undefined); +}); +test('project authorization uses root validated process proof and never sends control token to child port', async t => { + const requests = []; + let childRecord; + const {supervisor} = await fixture(t, (sup, _child, url, options) => { + requests.push(url); + const rootHealth = {...sup.expectedHealth(), ready: true, services: childRecord ? [childRecord] : []}; + if (url.endsWith('/authorize-project')) { + assert.equal(JSON.parse(options.body).port, 12345); + return response({record: childRecord, health: {...rootHealth, pid: childRecord.pid, + project_uuid: childRecord.project_uuid, project_path: childRecord.project_path}}); + } + return response(rootHealth); + }); + await supervisor.start(); + childRecord = {pid: 87654321, port: 12345, session_id: supervisor.sessionId, application_version: '0.1.0', source_commit: 'test-source', + project_uuid: 'ec845d76-ce6a-472e-aed5-b3ad651a06b8', project_path: '/physical/project', bound: true}; + assert.equal(await supervisor.authorizeProjectURL('http://127.0.0.1:12345/'), true); + assert.ok(requests.every(url => url.startsWith(supervisor.origin + '/'))); + await assert.rejects(supervisor.api('/api/desktop/health', {origin: 'http://127.0.0.1:12345'})); + childRecord.bound = false; + assert.equal(await supervisor.authorizeProjectURL('http://127.0.0.1:12345/'), false); + assert.equal(supervisor.origins.has('http://127.0.0.1:12345'), false); +}); diff --git a/desktop/tests/testing-install.test.cjs b/desktop/tests/testing-install.test.cjs new file mode 100644 index 0000000..6eb8419 --- /dev/null +++ b/desktop/tests/testing-install.test.cjs @@ -0,0 +1,261 @@ +'use strict'; +const {test}=require('node:test'); +const assert=require('node:assert/strict'); +const fs=require('node:fs/promises'); +const path=require('node:path'); +const os=require('node:os'); +const crypto=require('node:crypto'); +const {promisify}=require('node:util'); +const execFile=promisify(require('node:child_process').execFile); +const {installCompleteBundle}=require('../bootstrap.cjs'); +async function fixture(version='0.1.0') { + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-install-policy-')); + const source=path.join(root,'Downloads','Rieke OS.app'); + const runtime=path.join(source,'Contents/Resources/runtime'); + await fs.mkdir(runtime,{recursive:true});await fs.mkdir(path.join(source,'Contents/MacOS'),{recursive:true}); + await fs.writeFile(path.join(source,'Contents/MacOS/Rieke OS'),'native executable fixture',{mode:0o755}); + await fs.writeFile(path.join(source,'Contents/Info.plist'),`CFBundleIdentifierorg.riekeos.desktopCFBundleExecutableRieke OSCFBundleShortVersionString${version}LSMinimumSystemVersion14.0`); + const resources={}; + for(const name of ['python/bin/python3.11','mysql/bin/mysqld','mysql/bin/mysql','mysql/bin/mysqldump','application/python/workspace_desktop.py']){ + const file=path.join(runtime,name);await fs.mkdir(path.dirname(file),{recursive:true});await fs.writeFile(file,'immutable fixture',{mode:0o755}); + resources[name]={sha256:'79c3ce98db9b18e2c5fb3b1e74909c744e4f7b79a6c9ab5e6a0c538b0115cc50',size:17,executable:true}; + resources[name].sha256=crypto.createHash('sha256').update('immutable fixture').digest('hex'); + } + const manifest={format:'rieke-desktop-runtime',version:1,application_version:version,source_commit:'a'.repeat(40),parser_commit:'b'.repeat(40),source_dirty:false,platform:'darwin',architecture:'arm64',minimum_macos_version:'14.0',mysql_version:'8.4.2',python_version:'3.11.13',workspace_formats:[1],database_compatibility:1,resources}; + await fs.writeFile(path.join(runtime,'runtime-manifest.json'),JSON.stringify(manifest)); + const destination=path.join(root,'Applications','Rieke OS.app'); + const commands=[]; + async function run(command,args,options){ + commands.push([command,...args]); + if(command==='/usr/bin/codesign'&&args.includes('--verify'))return {stdout:'',stderr:''}; + if(command==='/usr/bin/codesign'||command==='/usr/sbin/spctl')throw new Error('Unsigned fixture is not Developer ID approved'); + if(command==='/bin/ps')return {stdout:'',stderr:''}; + if(command==='/usr/bin/ditto'){await fs.cp(args.at(-2),args.at(-1),{recursive:true,dereference:false});return {stdout:'',stderr:''};} + return execFile(command,args,options); + } + return {root,source,destination,run,commands,manifest}; +} +test('explicit unsigned testing Install and Open copies the whole verified app while signed defaults reject it',async()=>{ + const f=await fixture();try{ + await assert.rejects(installCompleteBundle(f),/Unsigned fixture/); + const result=await installCompleteBundle({...f,distribution:{channel:'unsigned-testing'}}); + assert.equal(result.destination,f.destination); + assert.equal(await fs.readFile(path.join(f.destination,'Contents/MacOS/Rieke OS'),'utf8'),'native executable fixture'); + assert.equal(await fs.readFile(path.join(f.destination,'Contents/Resources/runtime/mysql/bin/mysqld'),'utf8'),'immutable fixture'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +module.exports={fixture}; +test('native unsigned update helper rejects an exposed receipt before changing the installed app',async()=>{ + const {applyTestingInstall}=require('../testing-install.cjs'); + const f=await fixture();try{ + await installCompleteBundle({...f,distribution:{channel:'unsigned-testing'}}); + const receiptPath=path.join(f.root,'update.json');await fs.writeFile(receiptPath,'{}',{mode:0o644}); + await assert.rejects(applyTestingInstall({receiptPath,currentExecutable:path.join(f.destination,'Contents/MacOS/Rieke OS'),run:f.run}),/receipt.*private/i); + assert.equal(await fs.readFile(path.join(f.destination,'Contents/MacOS/Rieke OS'),'utf8'),'native executable fixture'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +async function updateFixture(){ + const f=await fixture('0.1.0'),fresh=await fixture('0.1.1'); + await installCompleteBundle({...f,distribution:{channel:'unsigned-testing'}}); + const cache=path.join(f.root,'updates','unsigned-testing');await fs.mkdir(cache,{recursive:true,mode:0o700}); + const candidate=path.join(cache,'Rieke OS.app');await fs.rename(fresh.source,candidate); + await fs.rm(fresh.root,{recursive:true,force:true}); + const archive=path.join(cache,'candidate.zip');await fs.writeFile(archive,'validated ZIP transport fixture',{mode:0o600}); + const {bundleDigest}=require('../bootstrap.cjs'),{sha256}=require('../testing-install.cjs'); + const currentExecutable=path.join(f.destination,'Contents/MacOS/Rieke OS'); + const receipt={format:'rieke-unsigned-testing-update',version:1,channel:'unsigned-testing',identifier:'org.riekeos.desktop',validated:true, + install_path:f.destination,current_executable:currentExecutable,current_pid:12345,current_created_at:17,current_version:'0.1.0',target_version:'0.1.1', + current_manifest_sha256:await sha256(path.join(f.destination,'Contents/Resources/runtime/runtime-manifest.json')), + runtime_manifest_sha256:await sha256(path.join(candidate,'Contents/Resources/runtime/runtime-manifest.json')), + archive_path:archive,archive_sha256:await sha256(archive),bundle_path:candidate,bundle_sha256:await bundleDigest(candidate)}; + const receiptPath=path.join(cache,'install.json');await fs.writeFile(receiptPath,JSON.stringify(receipt),{mode:0o600}); + return {...f,receipt,receiptPath,currentExecutable,cache}; +} +test('native unsigned update acknowledges readiness, waits exact current exit, installs compatible complete bundle and retains previous',async()=>{ + const {applyTestingInstall}=require('../testing-install.cjs'),{readBundleManifest}=require('../bootstrap.cjs'); + const f=await updateFixture();let ready=false,exited=false,identityReads=0; + try{ + const run=async(command,args,options)=>{ + if(command.endsWith('/python/bin/python3.11')){ + identityReads++;exited=identityReads>1; + return {stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify(exited?{pid:12345,alive:false}:{pid:12345,alive:true,created_at:17,executable:f.currentExecutable})+'\n'}; + } + if(command==='/usr/bin/open'){assert.equal(exited,true);assert.equal((await readBundleManifest(f.destination)).application_version,'0.1.1');return {stdout:''};} + if(command==='/usr/bin/ditto')assert.equal(ready&&exited,true,'No replacement before parent acknowledgement and exit'); + return f.run(command,args,options); + }; + const result=await applyTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,run,publishReady:()=>{ready=true;}}); + assert.equal(result.state,'Installed');assert.equal((await readBundleManifest(result.previous)).application_version,'0.1.0'); + assert.equal((await readBundleManifest(f.destination)).application_version,'0.1.1'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('failed native launch restores the previous complete app and requests its normal macOS launch',async()=>{ + const {applyTestingInstall}=require('../testing-install.cjs'),{readBundleManifest}=require('../bootstrap.cjs'); + const f=await updateFixture();let identities=0,opens=0; + try{ + const run=async(command,args,options)=>{ + if(command.endsWith('/python/bin/python3.11'))return {stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify(++identities===1?{pid:12345,alive:true,created_at:17,executable:f.currentExecutable}:{pid:12345,alive:false})+'\n'}; + if(command==='/usr/bin/open'){if(++opens===1)throw new Error('LaunchServices refused candidate');assert.equal((await readBundleManifest(f.destination)).application_version,'0.1.0');return {stdout:''};} + return f.run(command,args,options); + }; + const result=await applyTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,run,publishReady:()=>{}}); + assert.equal(result.state,'Restored');assert.equal(opens,2);assert.equal((await readBundleManifest(f.destination)).application_version,'0.1.0'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('controlled restore installs only the retained verified previous bundle and leaves update archive unnecessary',async()=>{ + const {applyTestingInstall,sha256}=require('../testing-install.cjs'),{readBundleManifest,bundleDigest}=require('../bootstrap.cjs'); + const f=await updateFixture();let identities=0; + try{ + const run=async(command,args,options)=>{ + if(command.endsWith('/python/bin/python3.11'))return {stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify(++identities===1?{pid:12345,alive:true,created_at:17,executable:f.currentExecutable}:{pid:12345,alive:false})+'\n'}; + if(command==='/usr/bin/open')return {stdout:''}; + return f.run(command,args,options); + }; + const installed=await applyTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,run,publishReady:()=>{}}); + const prior=JSON.parse(await fs.readFile(path.join(f.cache,'previous.json'),'utf8')); + const restore={...f.receipt,operation:'restore',current_version:'0.1.1',target_version:'0.1.0',bundle_path:installed.previous, + bundle_sha256:await bundleDigest(installed.previous),current_manifest_sha256:await sha256(path.join(f.destination,'Contents/Resources/runtime/runtime-manifest.json')), + runtime_manifest_sha256:f.receipt.current_manifest_sha256,archive_path:null,archive_sha256:null}; + const restorePath=path.join(f.cache,'restore.json');await fs.writeFile(restorePath,JSON.stringify(restore),{mode:0o600});identities=0; + await fs.rm(f.receipt.archive_path); + const result=await applyTestingInstall({receiptPath:restorePath,currentExecutable:f.currentExecutable,run,publishReady:()=>{}}); + assert.equal(result.state,'Restored');assert.equal((await readBundleManifest(f.destination)).application_version,'0.1.0'); + assert.equal(prior.previous_version,'0.1.0'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('Restore Previous defers a busy scientific session without launching helper or authorizing quit',async()=>{ + const {applyTestingInstall,restoreTestingPriorBundle}=require('../testing-install.cjs'),{readBundleManifest}=require('../bootstrap.cjs'); + const f=await updateFixture();let identities=0; + try{ + const run=async(command,args,options)=>{ + if(command.endsWith('/python/bin/python3.11'))return {stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify(++identities===1?{pid:12345,alive:true,created_at:17,executable:f.currentExecutable}:{pid:12345,alive:false})+'\n'}; + if(command==='/usr/bin/open')return {stdout:''};return f.run(command,args,options); + }; + await applyTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,run,publishReady:()=>{}}); + const result=await restoreTestingPriorBundle({app:{isPackaged:true,getPath:name=>name==='exe'?f.currentExecutable:f.root},manifest:await readBundleManifest(f.destination), + prepareQuit:async()=>({ready:false,busy:true}),authorizeQuit:()=>assert.fail('Busy session cannot quit'),spawnHelper:()=>assert.fail('Busy session cannot spawn helper'), + run:async(command,args,options)=>command.endsWith('/python/bin/python3.11')?{stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify({pid:Number(args.at(-1)),alive:true,created_at:17,executable:f.currentExecutable})+'\n'}:f.run(command,args,options)}); + assert.equal(result.busy,true);assert.equal((await readBundleManifest(f.destination)).application_version,'0.1.1'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('testing policy never replaces an app with any live installed process',async()=>{ + const f=await updateFixture();try{ + const run=async(command,args,options)=>command==='/bin/ps'?{stdout:' 23456 '+f.currentExecutable+'\n'}:f.run(command,args,options); + await assert.rejects(installCompleteBundle({source:f.receipt.bundle_path,destination:f.destination,distribution:{channel:'unsigned-testing'},run}),/running/); + assert.equal((await require('../bootstrap.cjs').readBundleManifest(f.destination)).application_version,'0.1.0'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('testing copy corruption outside runtime is rejected before retaining or replacing current app',async()=>{ + const f=await updateFixture();try{ + await fs.writeFile(path.join(f.receipt.bundle_path,'Contents/Resources/app.asar'),'published app code'); + const run=async(command,args,options)=>{ + const value=await f.run(command,args,options); + if(command==='/usr/bin/ditto')await fs.writeFile(path.join(args.at(-1),'Contents/Resources/app.asar'),'corrupted copied code'); + return value; + }; + await assert.rejects(installCompleteBundle({source:f.receipt.bundle_path,destination:f.destination,distribution:{channel:'unsigned-testing'},run}),/Copied application bundle checksum/); + assert.equal((await require('../bootstrap.cjs').readBundleManifest(f.destination)).application_version,'0.1.0'); + await assert.rejects(fs.stat(path.join(path.dirname(f.destination),'.Rieke OS.previous.app')),{code:'ENOENT'}); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('helper timeout leaves current app installed and never signals it or launches a replacement',async()=>{ + const f=await updateFixture();try{ + const run=async(command,args,options)=>{ + if(command.endsWith('/python/bin/python3.11'))return {stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify({pid:12345,alive:true,created_at:17,executable:f.currentExecutable})+'\n'}; + if(command==='/usr/bin/open')assert.fail('No launch while parent still alive');return f.run(command,args,options); + }; + await assert.rejects(require('../testing-install.cjs').applyTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,run,publishReady:()=>{},timeoutMs:1,pollMs:1}),/exit was not acknowledged/); + assert.equal((await require('../bootstrap.cjs').readBundleManifest(f.destination)).application_version,'0.1.0'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('prepared archive changed after readiness cannot replace current app',async()=>{ + const f=await updateFixture();let reads=0;try{ + const run=async(command,args,options)=>{ + if(command.endsWith('/python/bin/python3.11'))return {stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify(++reads===1?{pid:12345,alive:true,created_at:17,executable:f.currentExecutable}:{pid:12345,alive:false})+'\n'}; + return f.run(command,args,options); + }; + await assert.rejects(require('../testing-install.cjs').applyTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,run,publishReady:()=>{require('node:fs').writeFileSync(f.receipt.archive_path,'modified after acknowledgement');}}),/archive or bundle checksum differs/); + assert.equal((await require('../bootstrap.cjs').readBundleManifest(f.destination)).application_version,'0.1.0'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('helper readiness must match its spawned PID, current process, target version and archive before quit can proceed',async()=>{ + const f=await updateFixture();try{ + const directory=path.join(f.destination,'Contents/Resources/app.asar');await fs.mkdir(directory); + for(const file of ['testing-install.cjs','bootstrap.cjs','updater-validation.cjs','physical-fs.cjs'])await fs.copyFile(path.join(__dirname,'..',file),path.join(directory,file)); + const helper=require(await fs.realpath(path.join(directory,'testing-install.cjs'))); + const {EventEmitter}=require('node:events'),{PassThrough}=require('node:stream'); + const spawnHelper=()=>{ + const child=new EventEmitter();child.pid=777;child.stdout=new PassThrough();child.stderr=new PassThrough();child.unref=()=>{};child.kill=()=>assert.fail('No helper or current app force kill'); + setImmediate(()=>child.stdout.write('RIEKE_TESTING_INSTALL_READY='+JSON.stringify({pid:777,current_pid:12345,version:'0.0.1',archive_sha256:f.receipt.archive_sha256})+'\n')); + return child; + }; + const run=async(command,args,options)=>command.endsWith('/python/bin/python3.11')?{stdout:'RIEKE_PROCESS_IDENTITY='+JSON.stringify({pid:12345,alive:true,created_at:17,executable:f.currentExecutable})+'\n'}:f.run(command,args,options); + await assert.rejects(helper.launchTestingInstall({receiptPath:f.receiptPath,currentExecutable:f.currentExecutable,currentPid:12345,run,spawnHelper}),/readiness identity differs/); + assert.equal((await require('../bootstrap.cjs').readBundleManifest(f.destination)).application_version,'0.1.0'); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); +test('testing copy cannot silently lose the downloaded app quarantine attribute',async()=>{ + const f=await fixture();try{ + await execFile('/usr/bin/xattr',['-w','com.apple.quarantine','0083;00000001;RiekeFixture;',f.source]); + await assert.rejects(installCompleteBundle({...f,distribution:{channel:'unsigned-testing'}}),/quarantine attribute differs/); + await assert.rejects(fs.stat(f.destination),{code:'ENOENT'}); + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); + +test('actual Electron main and RUN_AS_NODE hash physical ASAR bytes and copy and remove the complete native bundle',async()=>{ + const f=await fixture();try{ + const archive=path.join(f.source,'Contents/Resources/app.asar'); + const contents=path.join(f.root,'asar-content');await fs.mkdir(contents); + await fs.writeFile(path.join(contents,'main.cjs'),'module.exports="owned archive fixture";'); + await require('@electron/asar').createPackage(contents,archive); + const expected=await require('../bootstrap.cjs').bundleDigest(f.source); + const archiveSHA=crypto.createHash('sha256').update(await fs.readFile(archive)).digest('hex'); + const electron=require('electron');const home=path.join(f.root,'home');await fs.mkdir(home); + const code=`const physical=require('original-fs').promises;const patched=require('node:fs/promises'); + const bootstrap=require(process.argv[1]);const helper=require(process.argv[2]); + const path=require('node:path');const {promisify}=require('node:util');const native=promisify(require('node:child_process').execFile); + (async()=>{const source=process.argv[3],home=process.argv[4],archive=path.join(source,'Contents/Resources/app.asar'); + const patchedVirtual=(await patched.lstat(archive)).isDirectory(); + const digest=await bootstrap.bundleDigest(source);const archiveSHA=await helper.sha256(archive); + const run=async(command,args,options)=>command==='/usr/bin/codesign'?{stdout:'',stderr:''}:native(command,args,options); + const installed=await bootstrap.installCompleteBundle({source,home,run,distribution:{channel:'unsigned-testing'},expectedBundleSha256:digest}); + const copied=(await physical.lstat(path.join(installed.destination,'Contents/Resources/app.asar'))).isFile(); + const copiedDigest=await bootstrap.bundleDigest(installed.destination); + await physical.rm(installed.destination,{recursive:true,force:true}); + console.log(JSON.stringify({patchedVirtual,digest,archiveSHA,copied,copiedDigest,removed:!(await physical.readdir(path.dirname(installed.destination))).length})); + })().catch(error=>{console.error(error);process.exitCode=1;});`; + const parameters=[path.resolve(__dirname,'../bootstrap.cjs'),path.resolve(__dirname,'../testing-install.cjs'),f.source,home]; + for(const mainProcess of [false,true]){ + const script=path.join(f.root,'owned-main.cjs'); + if(mainProcess)await fs.writeFile(script,`const ownedApp=require('electron').app;ownedApp.setPath('userData',require('node:path').join(process.env.HOME,'main-profile'));process.argv.splice(1,1);`+ + code.replace('process.exitCode=1;});','process.exitCode=1;}).finally(()=>ownedApp.exit(process.exitCode||0));')); + const result=await execFile(electron,mainProcess?[script,...parameters]:['-e',code,...parameters], + {env:{HOME:home,PATH:'/usr/bin:/bin',...(mainProcess?{}:{ELECTRON_RUN_AS_NODE:'1'})},timeout:20000}); + const proof=JSON.parse(result.stdout.trim().split('\n').find(line=>line.startsWith('{'))); + assert.equal(proof.patchedVirtual,true,'The actual Electron ASAR patch must be exercised'); + assert.equal(proof.digest,expected);assert.equal(proof.archiveSHA,archiveSHA); + assert.equal(proof.copied,true);assert.equal(proof.copiedDigest,expected);assert.equal(proof.removed,true); + } + }finally{await fs.rm(f.root,{recursive:true,force:true});} +}); + +test('native helper CLI loads from a real ASAR under Electron RUN_AS_NODE and safely defers an invalid private receipt',async()=>{ + const root=await fs.mkdtemp(path.join(os.tmpdir(),'rieke-native-helper-cli-'));try{ + const contents=path.join(root,'helper-content');await fs.mkdir(contents); + for(const file of ['testing-install.cjs','bootstrap.cjs','updater-validation.cjs','physical-fs.cjs']) + await fs.copyFile(path.join(__dirname,'..',file),path.join(contents,file)); + const archive=path.join(root,'app.asar');await require('@electron/asar').createPackage(contents,archive); + const home=path.join(root,'home'),cache=path.join(home,'profile/updates/unsigned-testing');await fs.mkdir(cache,{recursive:true}); + const receipt=path.join(cache,'install-test.json');await fs.writeFile(receipt,JSON.stringify({ + format:'rieke-unsigned-testing-update',version:1,channel:'unsigned-testing',identifier:'org.riekeos.desktop',validated:true}),{mode:0o600}); + const executable=require('electron'); + await assert.rejects(execFile(executable,[path.join(archive,'testing-install.cjs'),'--apply',receipt], + {env:{HOME:home,PATH:'/usr/bin:/bin',ELECTRON_RUN_AS_NODE:'1'},timeout:10000}),error=>{ + assert.equal(error.code,1);assert.ok(!error.stdout.includes('RIEKE_TESTING_INSTALL_READY=')); + assert.equal(error.stderr,'','Helper must reach its owned receipt failure handler');return true; + }); + const result=JSON.parse(await fs.readFile(receipt+'.result.json','utf8')); + assert.equal(result.state,'Deferred');assert.equal((await fs.stat(receipt+'.result.json')).mode&0o077,0); + assert.ok(!(await fs.readdir(home)).includes('Applications')); + }finally{await fs.rm(root,{recursive:true,force:true});} +}); diff --git a/desktop/update-recovery.cjs b/desktop/update-recovery.cjs new file mode 100644 index 0000000..e0d1a72 --- /dev/null +++ b/desktop/update-recovery.cjs @@ -0,0 +1,66 @@ +'use strict'; +const fs = require('./physical-fs.cjs').promises; +const path = require('node:path'); +const {spawn} = require('node:child_process'); +const {promisify} = require('node:util'); +const execFile = promisify(require('node:child_process').execFile); +const {signingIdentity, verifyResources} = require('./updater-validation.cjs'); +const {enclosingApp, compatibleManifest} = require('./bootstrap.cjs'); +const {atomicJSON} = require('./supervisor.cjs'); + +async function verifyPriorBundle({app, manifest, run = execFile}) { + const installedBundle = enclosingApp(app.getPath('exe')); + const directory = path.join(app.getPath('userData'), 'updates'); + const previous = path.join(directory, 'previous', 'Rieke OS.app'); + const receipt = JSON.parse(await fs.readFile(path.join(directory, 'previous.json'), 'utf8')); + const currentIdentity = await signingIdentity(installedBundle, run); + const priorIdentity = await signingIdentity(previous, run); + if (currentIdentity.team !== priorIdentity.team || currentIdentity.identifier !== priorIdentity.identifier || receipt.team !== priorIdentity.team || receipt.identifier !== priorIdentity.identifier) throw new Error('Previous app signing identity differs.'); + const runtime = path.join(previous, 'Contents', 'Resources', 'runtime'); + const previousManifest = JSON.parse(await fs.readFile(path.join(runtime, 'runtime-manifest.json'), 'utf8')); + if (!compatibleManifest(previousManifest, manifest) || previousManifest.mysql_version !== manifest.mysql_version || receipt.application_version !== previousManifest.application_version || receipt.source_commit !== previousManifest.source_commit) throw new Error('Previous app is incompatible with the current data contract.'); + await verifyResources(runtime, previousManifest.resources); + await run('/usr/sbin/spctl', ['--assess', '--type', 'execute', previous]); + return {previous, installedBundle, directory}; +} + +async function retainPriorBundle({app, manifest, run = execFile}) { + const installedBundle = enclosingApp(app.getPath('exe')); + const identity = await signingIdentity(installedBundle, run); + const directory = path.join(app.getPath('userData'), 'updates'); + await fs.mkdir(directory, {recursive: true, mode: 0o700}); + const staging = await fs.mkdtemp(path.join(directory, 'prior-stage-')); + const copied = path.join(staging, 'Rieke OS.app'); + try { + await run('/usr/bin/ditto', ['--rsrc', '--extattr', '--acl', installedBundle, copied], {timeout: 180000}); + const copiedIdentity = await signingIdentity(copied, run); + if (identity.team !== copiedIdentity.team || identity.identifier !== copiedIdentity.identifier) throw new Error('Previous app could not be retained with its signature intact.'); + const runtime = path.join(copied, 'Contents', 'Resources', 'runtime'); + const copiedManifest = JSON.parse(await fs.readFile(path.join(runtime, 'runtime-manifest.json'), 'utf8')); + if (copiedManifest.application_version !== manifest.application_version || copiedManifest.source_commit !== manifest.source_commit) throw new Error('Previous app identity differs.'); + await verifyResources(runtime, copiedManifest.resources); + const previous = path.join(directory, 'previous'); + const old = path.join(directory, 'previous-old'); + await fs.rm(old, {recursive: true, force: true}); + try { await fs.rename(previous, old); } catch (error) { if (error.code !== 'ENOENT') throw error; } + try { await fs.rename(staging, previous); } catch (error) { try { await fs.rename(old, previous); } catch {} throw error; } + await atomicJSON(path.join(directory, 'previous.json'), {format: 'rieke-desktop-previous', version: 1, ...identity, + application_version: manifest.application_version, source_commit: manifest.source_commit, + workspace_formats: manifest.workspace_formats, database_compatibility: manifest.database_compatibility, mysql_version: manifest.mysql_version}); + await fs.rm(old, {recursive: true, force: true}); + } finally { await fs.rm(staging, {recursive: true, force: true}); } +} + +async function restorePriorBundle({app, manifest, prepareQuit, authorizeQuit, run = execFile, spawnHelper = spawn}) { + if (!app.isPackaged) throw new Error('Recovery installation requires a signed installed app.'); + // No renderer-provided path, version or command participates in this boundary. + const {previous, installedBundle} = await verifyPriorBundle({app, manifest, run}); + const result = await prepareQuit(); + if (result?.ready !== true) return result; + const helper = spawnHelper(app.getPath('exe'), [path.join(__dirname, 'recovery-install.cjs'), String(process.pid), previous, installedBundle], + {detached: true, stdio: 'ignore', cwd: app.getPath('userData'), env: {HOME: process.env.HOME, TMPDIR: process.env.TMPDIR, ELECTRON_RUN_AS_NODE: '1'}}); + await new Promise((resolve, reject) => {helper.once('spawn', resolve); helper.once('error', reject);}); + helper.unref(); authorizeQuit(); app.quit(); + return {ready: true, restoring: true}; +} +module.exports = {verifyPriorBundle, retainPriorBundle, restorePriorBundle}; diff --git a/desktop/updater-validation.cjs b/desktop/updater-validation.cjs new file mode 100644 index 0000000..e9bb78e --- /dev/null +++ b/desktop/updater-validation.cjs @@ -0,0 +1,146 @@ +'use strict'; +const fs = require('./physical-fs.cjs').promises; +const path = require('node:path'); +const crypto = require('node:crypto'); +const {promisify} = require('node:util'); +const execFile = promisify(require('node:child_process').execFile); + +function stableVersion(value) { + if (typeof value !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(value)) throw new Error('Only stable semantic versions are accepted.'); + const parts = value.split('.').map(Number); + if (!parts.every(Number.isSafeInteger)) throw new Error('Invalid release version.'); + return parts; +} +function compareVersions(left, right) { + const a = stableVersion(left), b = stableVersion(right); + for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return Math.sign(a[i] - b[i]); + return 0; +} +function compatibleMacMinimum(minimum, host) { + function parts(value) { + if (typeof value !== 'string' || !/^\d+\.\d+(?:\.\d+)?$/.test(value)) throw new Error('Invalid macOS compatibility declaration.'); + const numbers=value.split('.').map(Number);while(numbers.length<3)numbers.push(0);return numbers; + } + const required=parts(minimum), actual=parts(host); + for(let index=0;index<3;index++){ + if(actual[index]>required[index])return true; + if(actual[index] candidate.workspace_formats.includes(format))) throw new Error('Update requires an unqualified database or workspace migration.'); + if (!candidate.resources || typeof candidate.resources !== 'object' || Array.isArray(candidate.resources) || !Object.keys(candidate.resources).length) throw new Error('Update has no resource inventory.'); + return candidate; +} +function safeResource(root, relative) { + if (typeof relative !== 'string' || relative.includes('\\') || relative.includes('\0') || relative.split('/').some(part => !part || part === '.' || part === '..') || path.isAbsolute(relative)) throw new Error('Unsafe runtime resource path.'); + return path.join(root, relative); +} +async function verifyResources(root, resources) { + const resolvedRoot = await fs.realpath(root); + const actualPaths = []; + async function inventory(directory) { + for (const entry of await fs.readdir(directory, {withFileTypes: true})) { + const file = path.join(directory, entry.name), relative = path.relative(root, file).split(path.sep).join('/'); + if (entry.isDirectory()) await inventory(file); + else if (!['runtime-manifest.json', 'runtime-audit.json'].includes(relative)) actualPaths.push(relative); + } + } + await inventory(root); + if (JSON.stringify(actualPaths.sort()) !== JSON.stringify(Object.keys(resources).sort())) throw new Error('Runtime resource inventory is incomplete or contains unexpected files.'); + for (const [relative, expected] of Object.entries(resources)) { + const file = safeResource(root, relative), stat = await fs.lstat(file); + const physical = await fs.realpath(file); + if (!physical.startsWith(resolvedRoot + path.sep)) throw new Error('Runtime resource escapes its bundle.'); + if (expected.symlink !== undefined) { + if (!stat.isSymbolicLink() || await fs.readlink(file) !== expected.symlink || path.isAbsolute(expected.symlink)) throw new Error('Runtime symlink differs from its manifest.'); + } else { + if (!stat.isFile() || stat.isSymbolicLink() || !/^[a-f0-9]{64}$/.test(expected.sha256) || stat.size !== expected.size) throw new Error('Runtime resource metadata is invalid.'); + if (typeof expected.executable === 'boolean' && expected.executable !== Boolean(stat.mode & 0o111)) throw new Error('Runtime executable permissions differ.'); + const actual = crypto.createHash('sha256'); + const handle = await fs.open(file, 'r'); + try { for await (const chunk of handle.createReadStream()) actual.update(chunk); } finally { await handle.close(); } + if (actual.digest('hex') !== expected.sha256) throw new Error('Runtime resource checksum failed.'); + } + } +} +async function signingIdentity(bundle, run = execFile) { + await run('/usr/bin/codesign', ['--verify', '--deep', '--strict', bundle]); + const result = await run('/usr/bin/codesign', ['-dv', '--verbose=4', bundle]); + const output = `${result.stdout || ''}\n${result.stderr || ''}`; + const team = output.match(/^TeamIdentifier=([A-Z0-9]+)$/m)?.[1]; + const identifier = output.match(/^Identifier=(.+)$/m)?.[1]; + if (!team || !identifier || !output.includes('Authority=Developer ID Application:')) throw new Error('A verified Developer ID application signature is required.'); + return {team, identifier}; +} +// ZIP extraction is always to an isolated disposable directory. Neither the +// manifest nor candidate code is ever executed during validation. +async function validateDownloadedCandidate({downloadedFile, version, manifest, cacheDirectory, installedBundle, run = execFile}) { + const installed = await signingIdentity(installedBundle, run); + if (installed.identifier !== 'org.riekeos.desktop') throw new Error('Unexpected installed app identity.'); + await fs.mkdir(cacheDirectory, {recursive: true, mode: 0o700}); + const temporary = await fs.mkdtemp(path.join(cacheDirectory, 'candidate-')); + try { + // Reject traversal before allowing a native extractor to touch disk. + const interpreter = path.join(installedBundle, 'Contents', 'Resources', 'runtime', 'python', 'bin', 'python3.11'); + await run(interpreter, ['-I', '-B', '-c', ARCHIVE_CHECK, downloadedFile], {timeout: 30000}); + await run('/usr/bin/ditto', ['-x', '-k', downloadedFile, temporary], {timeout: 180000}); + const bundles = (await fs.readdir(temporary)).filter(name => name.endsWith('.app')); + if (bundles.length !== 1 || bundles[0] !== 'Rieke OS.app') throw new Error('Update must contain exactly the expected app.'); + const bundle = path.join(temporary, bundles[0]); + const identity = await signingIdentity(bundle, run); + if (identity.team !== installed.team || identity.identifier !== installed.identifier) throw new Error('Update signer or application identity differs.'); + const plist = path.join(bundle, 'Contents', 'Info.plist'); + const declared = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleShortVersionString', plist]); + if (declared.stdout.trim() !== version) throw new Error('App version differs from update metadata.'); + const runtime = path.join(bundle, 'Contents', 'Resources', 'runtime'); + const candidate = compatibleCandidate(JSON.parse(await fs.readFile(path.join(runtime, 'runtime-manifest.json'), 'utf8')), manifest, version); + const host = await run('/usr/bin/sw_vers', ['-productVersion']); + const bundleMinimum = await run('/usr/libexec/PlistBuddy', ['-c', 'Print :LSMinimumSystemVersion', plist]); + compatibleMacMinimum(candidate.minimum_macos_version, host.stdout.trim()); + if(bundleMinimum.stdout.trim() !== candidate.minimum_macos_version)throw new Error('App and runtime macOS minimums differ.'); + await verifyResources(runtime, candidate.resources); + await run('/usr/sbin/spctl', ['--assess', '--type', 'execute', '--verbose=2', bundle]); + const hasher = crypto.createHash('sha256'); + const handle = await fs.open(downloadedFile, 'r'); + try {for await (const chunk of handle.createReadStream()) hasher.update(chunk);} finally {await handle.close();} + return {version, team: identity.team, identifier: identity.identifier, downloadedFile, archive_sha256: hasher.digest('hex'), validated: true, native_staging_verified: false, startup_health_verified: false}; + } finally { await fs.rm(temporary, {recursive: true, force: true}); } +} +const ARCHIVE_CHECK = String.raw` +import posixpath, stat, sys, zipfile +with zipfile.ZipFile(sys.argv[1]) as archive: + entries=archive.infolist() + if not entries or len(entries)>100000 or sum(e.file_size for e in entries)>6*1024**3: raise ValueError('Archive bounds') + names=set(); links={} + for entry in entries: + name=entry.filename.rstrip('/') + if not name or name.startswith('/') or chr(92) in name or chr(0) in name or any(p in ('','..','.') for p in name.split('/')): raise ValueError('Archive path') + if name in names: raise ValueError('Duplicate archive path') + names.add(name) + mode=entry.external_attr>>16 + if stat.S_IFMT(mode) and not (stat.S_ISREG(mode) or stat.S_ISDIR(mode) or stat.S_ISLNK(mode)): raise ValueError('Archive special file') + if stat.S_ISLNK(mode): + if entry.file_size>4096: raise ValueError('Archive link size') + target=archive.read(entry).decode('utf8') + if target.startswith('/') or chr(92) in target: raise ValueError('Archive link') + links[name]=target + for name in names: + resolved=name + for _ in range(40): + parts=resolved.split('/'); changed=False + for i in range(1,len(parts)+1): + prefix='/'.join(parts[:i]) + if prefix in links: + resolved=posixpath.normpath(posixpath.join(posixpath.dirname(prefix),links[prefix],*parts[i:])) + if resolved=='..' or resolved.startswith('../') or resolved.startswith('/'): raise ValueError('Archive link escape') + changed=True; break + if not changed: break + else: raise ValueError('Archive link loop') +`; +module.exports = {stableVersion, compareVersions, compatibleMacMinimum, compatibleCandidate, safeResource, verifyResources, signingIdentity, validateDownloadedCandidate, ARCHIVE_CHECK}; diff --git a/desktop/updater.cjs b/desktop/updater.cjs new file mode 100644 index 0000000..ed3ee3e --- /dev/null +++ b/desktop/updater.cjs @@ -0,0 +1,148 @@ +'use strict'; +const fs = require('./physical-fs.cjs').promises; +const path = require('node:path'); +const {compareVersions, signingIdentity, validateDownloadedCandidate} = require('./updater-validation.cjs'); + +function createUpdateCoordinator({app, manifest, publishStatus = () => {}, prepareQuit, authorizeQuit = () => {}, revokeQuit = () => {}, onInstallationFailure = () => {}, updater, verifyCandidate = validateDownloadedCandidate, verifyInstalled = signingIdentity, retainPrevious = options => require('./update-recovery.cjs').retainPriorBundle(options), receiptPath, timers = globalThis, random = Math.random, enabled, installedBundle}) { + const cacheDirectory = path.join(app.getPath('userData'), 'updates'); + receiptPath ||= path.join(cacheDirectory, 'status.json'); + installedBundle ||= path.resolve(app.getPath('exe'), '../../..'); + let status = {state: 'Current', installed: manifest.application_version, available: null, message: 'Using the installed version.'}; + let pending = null, checking = null, installing = null, timer = null, stopped = false, active = false, validation = null; + let receiptWrites = Promise.resolve(); + const listeners = []; + async function verifyPendingArchive() { + if (!pending?.archive_sha256) return; + const crypto = require('node:crypto'), hasher = crypto.createHash('sha256'); + const handle = await fs.open(pending.downloadedFile, 'r'); + try {for await (const chunk of handle.createReadStream()) hasher.update(chunk);} finally {await handle.close();} + if (hasher.digest('hex') !== pending.archive_sha256) throw new Error('Prepared archive changed'); + } + function set(state, fields = {}) { + status = {...status, ...fields, state}; + publishStatus({...status}); + const snapshot = {format: 'rieke-desktop-update-status', version: 1, installed: status.installed, available: status.available, state, validated: pending?.version || null, checked_at: status.checked_at || null}; + receiptWrites = receiptWrites.catch(() => {}).then(async () => { + await fs.mkdir(path.dirname(receiptPath), {recursive: true, mode: 0o700}); + const temporary = receiptPath + '.tmp'; + await fs.writeFile(temporary, JSON.stringify(snapshot) + '\n', {mode: 0o600}); + await fs.rename(temporary, receiptPath); + }).catch(() => {}); + return {...status}; + } + function defer(message) { return set(pending ? 'Ready' : 'Deferred', {available: pending?.version || status.available, message, check_error: message}); } + const on = (event, listener) => {updater.on(event, listener); listeners.push([event, listener]);}; + async function downloaded(event) { + if (!active || stopped) return; + set('Validating', {available: event.version, message: 'Verifying downloaded app identity and compatibility.'}); + // MacUpdater's native proxy now refers to this event's ZIP. A previous + // candidate can no longer authorize that proxy if this ZIP is rejected. + pending = null; + try { + const candidate = await verifyCandidate({downloadedFile: event.downloadedFile, version: event.version, manifest, cacheDirectory, installedBundle}); + await retainPrevious({app, manifest}); + if (!active || stopped) return; + pending = candidate; + set('Ready', {available: candidate.version, native_staging_verified: false, startup_health_verified: false, message: 'Update verified and prepared for an orderly quit. Native installation and startup health are checked separately.'}); + } catch { + defer('The downloaded update was rejected. The installed app remains usable.'); + } + } + function schedule() { + if (stopped || !active) return; + timer = timers.setTimeout(async () => {await check(); schedule();}, Math.round(3600000 * (0.9 + random() * 0.2))); + timer?.unref?.(); + } + async function check() { + if (!active || stopped) return {...status}; + if (pending) return {...status}; + if (checking) return checking; + if (['Downloading', 'Validating', 'Draining', 'Installing'].includes(status.state)) return {...status}; + checking = (async () => { + set('Checking', {checked_at: new Date().toISOString(), check_error: null, message: 'Checking for a published update.'}); + try { + const result = await updater.checkForUpdates(); + // The pinned client resolves metadata before its automatic download. + // Observe that separate promise so a failed checksum/network write + // cannot escape as an unhandled rejection in the Electron main process. + if (result?.downloadPromise) await result.downloadPromise; + } catch { defer('Update check unavailable. The installed app remains usable.'); } + return {...status}; + })().finally(() => {checking = null;}); + return checking; + } + async function start() { + if (active || stopped) return {...status}; + // Receipts are display hints only: a previous Ready never authorizes install. + try { + const previous = JSON.parse(await fs.readFile(receiptPath, 'utf8')); + if (previous.format === 'rieke-desktop-update-status' && previous.version === 1 && previous.installed === manifest.application_version && previous.validated) status.available = previous.available; + } catch {} + if (enabled === false || !app.isPackaged || process.platform !== 'darwin' || process.arch !== 'arm64') return set('Deferred', {message: 'Automatic updates require a qualified signed macOS Apple Silicon installation.'}); + try { await verifyInstalled(installedBundle); } catch { return set('Deferred', {message: 'Automatic updates are disabled for this unsigned development build.'}); } + updater ||= require('electron-updater').autoUpdater; + updater.autoInstallOnAppQuit = false; + updater.autoDownload = true; + updater.autoRunAppAfterInstall = false; + updater.allowDowngrade = false; + updater.allowPrerelease = false; + updater.logger = null; // Never log cache/session URLs or local paths. + updater.setFeedURL({provider: 'github', owner: 'maxwellsdm1867', repo: 'Rieke-OS', private: false}); + on('checking-for-update', () => set('Checking')); + on('update-available', info => { + try { + if (compareVersions(info.version, manifest.application_version) <= 0) throw new Error('Older release'); + set('Available', {available: info.version, release_url: `https://github.com/maxwellsdm1867/Rieke-OS/releases/tag/v${info.version}`, message: `Rieke OS ${info.version} is available.`}); + } catch { updater.autoDownload = false; defer('Published update metadata was rejected.'); } + }); + on('download-progress', progress => set('Downloading', {progress: Math.max(0, Math.min(100, Number(progress.percent) || 0)), message: 'Downloading an update quietly.'})); + on('update-not-available', () => set(pending ? 'Ready' : 'Current', {message: pending ? 'The verified pending update remains prepared.' : 'The installed version is current.'})); + on('update-downloaded', event => { validation = downloaded(event); }); + on('error', () => { + if (status.state === 'Installing') { + revokeQuit(); + defer('Native installation failed. Restart the installed app from recovery.'); + onInstallationFailure(); + } else defer('Update preparation failed. The installed app remains usable.'); + }); + active = true; + await check(); + schedule(); + return {...status}; + } + async function installPrepared() { + if (installing) return installing; + if (validation) await validation; + if (installing) return installing; + if (!pending || status.state !== 'Ready') return {ready: false, reason: 'No verified update is prepared.'}; + installing = (async () => { + set('Draining', {message: 'Saving drafts and waiting for all scientific services to close.'}); + if (pending.archive_sha256) { + try { await verifyPendingArchive(); } + catch { pending = null; defer('The prepared update changed or is missing. Installation is deferred.'); return {ready: false, reason: status.message}; } + } + let result; + try { result = await prepareQuit(); } catch { result = {ready: false}; } + if (result?.ready !== true) { + set('Ready', {message: 'Update remains pending: a draft, writer or service has not acknowledged closure.'}); + return {ready: false, reason: result?.reason || status.message}; + } + // Drain can take long enough for a cached ZIP to change. Check the exact + // validated bytes again at the installation boundary. Services are already + // closed here, so failed verification must offer backend recovery. + try { await verifyPendingArchive(); } + catch { + pending = null; revokeQuit(); + defer('The prepared update changed during shutdown. Restart the installed app from recovery.'); + onInstallationFailure(); return {ready: false, reason: status.message}; + } + set('Installing', {message: 'All owned services have closed; handing the verified app to the native installer.'}); + try { authorizeQuit(); updater.quitAndInstall(); return {ready: true, installing: true}; } + catch { revokeQuit(); defer('Native installation failed. Use recovery to restart the installed app.'); onInstallationFailure(); return {ready: false, reason: status.message}; } + })().finally(() => {installing = null;}); + return installing; + } + function stop() { stopped = true; active = false; if (timer) timers.clearTimeout(timer); for (const [event, listener] of listeners) updater.removeListener(event, listener); } + return {getStatus: () => ({...status}), check, start, stop, installPrepared}; +} +module.exports = {createUpdateCoordinator}; diff --git a/docs/DATA_EFFICIENCY_AUDIT.md b/docs/DATA_EFFICIENCY_AUDIT.md new file mode 100644 index 0000000..05a3e1d --- /dev/null +++ b/docs/DATA_EFFICIENCY_AUDIT.md @@ -0,0 +1,140 @@ +# Rieke OS data-efficiency audit — 2026-09-29 + +**Conclusion:** the raw-signal loading design is sound, and the remaining scientific SQL data is small. The biggest remaining problems are repeated ancestor metadata, work tied to whole-project state rather than the requested operation, and derived/history data with no lifecycle. Fix those before reconsidering the database engine. + +This is a code and data-lifecycle audit, not a request to enforce an arbitrary byte budget. A representation earns its storage by serving a current feature, recovery requirement, or deliberate scientific export. Recomputable copies need a clear invalidation and reclamation path. + +## Scope and evidence + +Inspected the active app checkout at `/Users/maxwellsdm/Documents/GitHub/epicTreeGUI`, including the recent persistence changes. Compared core modules with `/Users/maxwellsdm/Documents/GitHub/Rieke-OS`; snapshot, cache, index, explorer, curation, and MATLAB modules matched at measurement time. Service/API/SQLite-export modules differ between checkouts; source hashes are recorded in the measurements. Findings refer to the active checkout unless stated otherwise. + +Read live SRM database metadata and records in a read-only SQL transaction, inspected SQLite files read-only, and sampled GETs and the read-only annotation POST. No scientific records or application code were changed by this audit. Its read-only POST exercises the existing snapshot hook; unchanged snapshots were not rewritten. This was not a concurrent-user or large-project stress test. + +Evidence: [measurements](dev/data-efficiency-audit/measurements.json), [local measurement runner](dev/data-efficiency-audit/measure.py). HTTP timings are medians of three local requests, not service-level guarantees. JSON sizes are decoded/uncompressed representations unless explicitly labeled gzip. SQL `information_schema` row counts are estimates; the separately reported revision counts are exact. + +| Measured item | Result | +|---|---:| +| SRM epochs / cells / sources | 1,776 / 8 / 2 | +| Database directory, allocated | 167.9 MiB | +| Parsed imports, allocated | 38.9 MiB | +| Metadata indexes, allocated | 104.9 MiB | +| Compressed source projections, allocated | 20.5 MiB | +| Exports, allocated | 57.9 MiB | +| State snapshot | 538,865 bytes | +| Snapshot excluding export recipes | 31,971 bytes | +| SQL explorer revisions / active bindings | 28 / 5 | +| Epoch references across SQL explorer recipes | 6,886 | +| Explorer recipe JSON in MySQL | 1,577,166 bytes | + +## Prioritized findings + +### 1. High: the snapshot hook runs on read-only POSTs and captures too much + +[API hook](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_api.py:1416), [capture](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_snapshot.py:34), [query compaction](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_snapshot.py:99). + +Every successful POST/PUT/PATCH/DELETE performs a synchronous snapshot while holding the shared database lock. POST is also used for annotation reads, tree pages, predicate previews, and membership queries. These operations can therefore rebuild backup state without changing anything. The equality check prevents a final file write, but occurs **after** reading SQL, decoding JSON, sorting, rerunning pinned queries, and serializing the snapshot. + +`capture()` also fetches all explorer/preset versions before filtering to active ones in Python. On this small project, capture alone used 26 SQL queries, fetched approximately 2.21 MB in serialized result representations, took 53–73 ms, and peaked at 7.33 MiB of traced Python allocations. These figures exclude pinned-query compaction. A 401-byte annotation-read response took a median 121 ms; this is an observed endpoint time, not an isolated attribution of all latency to the hook. + +**Change:** mark actual committed state mutations, snapshot only when that state revision changes, select active revisions in SQL, and separate immutable export recipes from current settings. Keep transaction/backup-failure semantics explicit rather than simply making backups fire-and-forget. + +**Acceptance:** repeated annotation reads, previews, and tree-page requests perform zero snapshot captures; a tag save creates one recoverable checkpoint; snapshot work does not scale with obsolete revision history. Retain the existing restore and crash-recovery tests. + +### 2. High: each epoch carries a large copy of its block metadata + +[Detail construction](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py:273), [per-epoch index storage](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py:74), [detail cache](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py:396). + +The inspected epoch response was 123,639 bytes. Its block metadata accounted for 112,287 bytes, including a **111,371-byte `frameTimesMs` array**. That block contains 430 epochs. The block array is copied into each epoch's serialized detail record and reconstructed on each uncached detail read. The current 64-entry detail cache holds independent decoded copies, so compression on disk hides repeated decoding and allocation. + +Serializing that shared array for all 430 epoch details represents approximately 45.7 MiB of repeated JSON. This is a representation-volume calculation, not a claim of 45.7 MiB extra physical disk or simultaneous RAM. + +**Change:** store source/cell/group/block metadata once under immutable identity plus version; let epoch details reference it. Fetch and cache block context separately when needed. Preserve the recorded frame-time arrays exactly—do not discard them or infer an epoch-to-array mapping without validating the acquisition format. + +**Acceptance:** inspecting many epochs in one block fetches/decodes the shared block object once; scientific metadata and legacy/export round trips remain exact. + +### 3. High: obsolete cache generations are never reclaimed + +[Generation selection](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py:380), [index publication](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py:140), [projection writer](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_projection_cache.py:42). + +There are **seven complete indexes**, each covering the same 1,776 epochs. They total 100.3 MiB logical / 104.9 MiB allocated; one index is 14.3 MiB logical. Source projections add another 20.5 MiB allocated. Changed signatures/code produce new filenames; cleanup removes temporary build files, not superseded published generations. + +**Change:** introduce ownership/reference tracking for active generations and collect unreferenced indexes and projections after successful publication. A small explicit rollback set can be retained if it serves a real workflow. Do not remove a generation still referenced by a running reader. + +**Acceptance:** repeated metadata refreshes/upgrades cease increasing retained cache generations once readers release old ones; unchanged restarts reuse the current index; interrupted rebuilds keep the last valid generation. + +### 4. Medium: query-based recovery does not yet make live SQL pins query-based + +[Revision creation](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_explorer.py:125), [recipe cache](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_explorer.py:58). + +The recent backup optimization removes epoch lists from reproducible pins **in the backup**. Live `ExplorerHistory.create()` still stores a complete epoch list, UUID diff lists, and provenance in every new revision. There are 28 revisions containing 6,886 epoch references for five active bindings. `_recipe_cache` is also keyed by revision UUID without eviction. + +The present 1.50 MiB of recipe JSON is modest. The concern is growth proportional to selected epochs × applied revisions, even when the source recordings do not change. This is not a reason to delete existing frozen history blindly: bindings, parents, and exports can refer to it. + +**Change:** represent ordinary working pins as predicates + exact source/metadata versions + result digest, with sparse explicit overrides where a selection is not reproducible. Retain explicit frozen export records. Reclaim unreferenced materialized memberships and evict retired recipe-cache entries after auditing dependencies. + +**Acceptance:** repeatedly applying a large unchanged query does not append another full epoch list; edited/tag-dependent subsets and immutable exports retain their scientific meaning. + +### 5. Medium: the overview mostly transports historical event detail + +[Overview events](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py:623), [five visible events](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/workspace-app/src/components/Overview.jsx:34). + +The overview response was 284,851 bytes; its `events` value alone was 265,071 bytes (about 93%). The server includes 25 full events while the view displays five. Old provenance-heavy events remain large even though routine new edits no longer create them. With gzip, the complete response body was 40,774 bytes: compression helps transport, but not SQL decoding and constructing the original JSON objects. + +**Change:** return a small activity summary for the visible items. Load a selected event's full evidence through the existing detail endpoint. Keep detailed history where the user requests it. + +**Acceptance:** overview does not retrieve full event payloads; opening an event still retrieves the original evidence. + +### 6. Medium: bounded page responses still require whole-scope work + +[Filtered rows](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py:572), [epoch pagination](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py:637), [temporary query scope](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py:172), [export-membership copy](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_curation.py:397). + +A one-epoch page is small on the wire, but `filtered_rows()` constructs/decorates/sorts the whole protocol membership before slicing. Query helpers create and populate a temporary scope table for each call, and predicate matching materializes Python sets. Protocol binding access deep-copies the full recipe. Some summary paths deep-copy the project-wide export-membership index as well. + +The measured one-epoch page was 3,793 bytes and 54 ms median. This small-project number does not establish a problem at present; the implementation establishes that work is not bounded by page size. + +**Change:** reuse immutable query results by generation, push indexed filtering/order/pagination into the disk index where semantics permit, and return memberships for the requested scope rather than cloning all export links. + +**Acceptance:** benchmark fixed-size pages at increasing epoch and export counts, checking CPU, rows visited, and peak memory—not just response size. Preserve exact typing, null/missing distinctions, and anchor ordering. + +### 7. Medium: cold rebuild and MATLAB export can defeat lazy metadata loading + +[Index build](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py:85), [cold source JSON load](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py:418), [MATLAB catalog construction](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matlab.py:139). + +Changed generations build a complete new index. On a projection-cache miss, the full source JSON is decoded before index construction. Warm loading still keeps lightweight rows/fingerprints for every epoch in memory; only detailed metadata is lazy. + +The MATLAB export builder separately runs `catalog(list(service.rows.values()), service.details, ...)` for the whole project before cataloging its selected records. A small export can therefore visit detailed metadata for unrelated epochs. The SQLite exporter also receives an already materialized complete package and hashes a complete serialized representation; it is not a streaming export pipeline. + +**Change:** reuse the sealed index's schema/catalog for MATLAB exports, project only selected IDs/fields, and stream large export records where integrity checks allow. For ingestion growth, build per-source partitions or incrementally merge additions rather than rebuilding unchanged sources. + +**Acceptance:** a small MATLAB export does not decode unrelated epoch details; cold/import benchmarks report peak memory and temporary disk alongside elapsed time. The older repository benchmark of 50,000 epochs reports a 63-second full index build and a 238 MB index; it is historical fixture evidence, not a new production measurement. + +### 8. Medium: daily state backups repeatedly embed immutable exports + +[Captured state tables](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_snapshot.py:17), [daily snapshot](/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_snapshot.py:194). + +Current settings/query/edit state is 31,971 bytes, while the complete snapshot is 538,865 bytes because it includes seven existing export recipes. On each active new UTC date a complete new SQLite snapshot is written, even if the state is identical. At the current logical payload alone, 365 active days would repeat about 188 MiB. That is arithmetic, not an observed annual workload. + +**Change:** store immutable export recipes once by content hash and reference them from compact state snapshots; make each recovery package's dependencies explicit and verified. Deduplicate identical daily content. Preserve independent backups where they are intentional—deduplication is not a reason to leave recovery dependent on missing files. + +**Acceptance:** adding a day of unchanged state does not duplicate every frozen export recipe; restoring a packaged snapshot works without the original live SQL server and detects missing immutable objects. + +## What is already appropriate + +- Raw traces are read from H5 in bounded windows of at most 100,000 samples. They are not copied into scientific SQL waveform rows. +- Source SHA verification is cached by file signature. A first trace can require a full source checksum read; that integrity cost is distinct from eagerly loading waveforms into memory. +- The SQLite detail cache is limited to 64 entries. The frontend epoch cache has entry, estimated-byte, and TTL bounds; adjacent prefetch is limited to metadata for two epochs. There is no evidence here of unbounded raw-trace caching. +- Typed field values and exported parameter sets already have deduplication. Export files intentionally contain queryable metadata plus a compressed exact archive; the measured frozen-record archive is only roughly 9–14% of each inspected SQLite export. Do not call all of that redundancy waste or remove reproducibility checks casually. +- Tags use stable target/author identities and current-state updates. Query last-run state updates a row per distinct predicate rather than appending one per execution. No-op shared-tag and layout saves are already handled. +- The reduced redo allocation and durable-commit settings should remain. Disabling crash recovery is not an efficiency improvement. + +## Recommended order + +1. Fix snapshot triggering and SQL projection; remove heavyweight event payloads from overview. +2. Normalize shared block/ancestor metadata and add cache-generation reclamation. +3. Move ordinary live pins to query/version descriptors and audit history dependencies. +4. Address page-level work, small-export behavior, and incremental ingestion with representative larger fixtures. +5. Deduplicate immutable objects in recovery archives while testing full restore bundles. + +A reusable efficiency check for every new feature: identify its authoritative data; list every retained copy; distinguish configuration, cache, and frozen scientific output; specify invalidation/reclamation; measure bytes read/written and objects decoded for a common operation; test growth with data size and operation count separately; then verify recovery from the retained representations. + +The storage reduction already completed remains valid. This audit identifies additional work; it does not claim the whole data lifecycle has already been optimized. diff --git a/docs/STORAGE_RECOVERY.md b/docs/STORAGE_RECOVERY.md index 646848c..d2d0f94 100644 --- a/docs/STORAGE_RECOVERY.md +++ b/docs/STORAGE_RECOVERY.md @@ -6,34 +6,79 @@ queries, layouts, or inclusion decisions. ## What is saved -`app-state.json` is an atomic current-state snapshot. It includes: +`app-state.json` locates the compact current-state recovery database under +`backups/app-state/current-.sqlite`. Together they protect: - Project settings and protocol configuration files. - Named predicates/presets, layouts, and the latest run of each distinct query (predicate, splits, run time, source identities, and query/metadata versions). -- Current annotation profiles, sparse cell/epoch tags, and curation decisions. +- Current annotation profiles, cell/epoch tags, and curation decisions, including + densely tagged datasets with several tags and authors per target. - Current pinned queries with source H5 checksums, metadata checksums, version - information, and a digest of the expected result. Recoverable pins do not - enumerate all epochs: recovery reruns their predicates and verifies the digest. + information, and their exact frozen epoch membership and metadata fingerprints. - Existing export records and their immutable recipes. Export artifacts and H5 recordings remain separate files and must also be retained. -An existing frozen subset that a saved predicate cannot reproduce retains its -explicit membership. It is never silently widened on recovery. UUIDs remain -necessary for explicitly tagged/edited cells and epochs. - -Successful API writes update the snapshot; unchanged state does not rewrite it. -Startup and successful writes create one write-once SQLite snapshot per active -UTC day under `backups/app-state/YYYY-MM-DD.sqlite`. A day without running the app -has no scheduled backup. These daily files record the first captured state that -day; `app-state.json` holds the latest successful capture. No H5 data or derived -metadata caches are copied into them. - -Routine query runs, tag/curation edits, layout saves, and preset saves no longer -append action events. Each distinct query has a current/latest-run record, not a -record per execution. Existing history and scientific import/export/external -exchange receipts remain available. Explicit export/version workflows remain -unchanged. +Tag associations use target and profile UUIDs; display names do not establish +identity. New backups retain explicit frozen membership, so later tag edits +cannot change a pin during recovery. Older query-based backups remain readable +and must reproduce their recorded membership digest before restore succeeds. + +Direct cell/epoch tag edits commit their current rows and an append-only change +event together in MySQL. The API acknowledges that database commit immediately; +it does not wait for a separate recovery copy or a page refresh. A burst of tag +edits queues one background recovery capture after one second of inactivity, +with a five-second maximum scheduling delay while edits continue. Lock contention +or a failed capture can extend that delay. The response and `/api/backup/status` +report pending, running, current, or degraded backup state. Normal database crash +recovery still preserves acknowledged commits; loss of the database before the +independent capture finishes can lose those newest edits from the recovery copy. +Clean project close forces the recovery capture and refuses to finish if it fails. + +On supported native databases, a verified change tracker copies only changed +records into that recovery database. Rows and the coverage watermark commit +together. An unknown change gap, changed schema/server identity, or unsupported +database requires a full current-state capture. Other successful mutations still +wait for the recovery write; a failed write returns `507` with `saved: true` and +must not be blindly replayed as a new edit. + +Startup and recovery captures also create a write-once checkpoint for the active +UTC day under `backups/app-state/checkpoint-v2-YYYY-MM-DD.sqlite`. It records the +first capture that day; the current recovery database holds the latest capture. +No background schedule runs on inactive days. New checkpoint history keeps at +most two checkpoints within a combined 128 MiB budget, except that the newest +checkpoint is retained even if it alone exceeds that budget. Current state is +always retained. Old-format backups and explicit before-restore copies are +preserved separately. H5 signals and derived metadata indexes are not copied +into these app-state files. + +The JSON pointer alone is not a standalone backup. Keep it with its referenced +SQLite file, or use a sealed daily checkpoint for an independent app-state copy. +Use the complete project transfer workflow to include recordings and exports. + +Shared cell/epoch tag batches append one event containing their before/after +values in the same transaction as the edit. Routine query runs, curation edits, +layout saves, and preset saves retain current state without a new event for each +operation. Each distinct query has a current/latest-run record. Existing history +and scientific import/export/external exchange receipts remain available. The +app-state mirror restores current state, not the append-only event history; a +full SQL backup includes that history. + +Ordinary shared-tag filtering uses a persistent MySQL lookup. Existing projects +build it once during preparation; database triggers maintain changed memberships +in the same transaction as each canonical tag edit, including external SQL +writes. Clean reopen reuses it after checking fresh canonical content, the +lookup table identity, and its schema and triggers. Missing triggers, replaced +tables, or an unclean checkpoint cause validation or rebuilding before reuse. +The autocomplete dictionary keeps current tag names, distinct-target usage +counts, and author references. Prefix keys use Python's exact Unicode casefold +semantics and are computed once for each new name. Database triggers maintain +counts with the same transaction as the tag edit, including external SQL writes. +These tables are rebuildable indexes, not additional canonical annotation copies. +There is no full SQLite tag-cache build on the ordinary native filtering path. +Full aggregate views and unsupported database contracts retain their existing +canonical/derived readers. Cell tags remain one cell record per author, joined +to their child epochs by UUID. Durable SQL autosave remains enabled. ## Recovery @@ -46,12 +91,13 @@ app server** first, leaving its database available. From the application checkou ```sh PYTHONPATH=python .rieke-runtime/venv/bin/python python/workspace_state_snapshot.py \ --project-dir /path/to/project \ - --restore /path/to/project/backups/app-state/YYYY-MM-DD.sqlite + --restore /path/to/project/backups/app-state/checkpoint-v2-YYYY-MM-DD.sqlite ``` -The same command accepts `app-state.json`. Restore refuses a running app, a +The same command accepts `app-state.json` with its referenced database, or older +JSON/SQLite snapshots. Restore refuses a running app, a foreign project, changed source/metadata identities, corrupted SQLite snapshots, -or a pinned query whose reconstructed result differs. It saves the immediate +or an older pinned query whose reconstructed result differs. It saves the immediate pre-restore configuration under `backups/app-state/before-restore-*.json`, changes SQL state transactionally, and restores configuration files if an ordinary error occurs. An interrupted restore leaves a marker that prevents app startup until diff --git a/docs/WORKSPACE_SHARING_AND_UPDATES.md b/docs/WORKSPACE_SHARING_AND_UPDATES.md index 9f9caaf..d6f82cf 100644 --- a/docs/WORKSPACE_SHARING_AND_UPDATES.md +++ b/docs/WORKSPACE_SHARING_AND_UPDATES.md @@ -2,15 +2,62 @@ ## Choose the project folder itself +The **+** in the left project rail opens a popup over the current workspace. +Choose either project action inside it. The workspace remains visible; **×** +or **Escape** closes the popup and returns focus to **+**. Creating a new +project from the welcome screen also opens a popup. + +Every project location field has **Browse…**. Choose folders using the local +folder picker; paths remain editable. New projects can use an existing empty +folder or a named new folder inside a chosen location. Move, share and restore +destinations ask for a new folder name. Browsing only selects a path; it does not +create or modify files. Cancel the folder picker to return to setup unchanged. + +New project setup ends with **Cancel** and **Create & open**. **Cancel** closes +the popup and returns to the visible workspace. + +The left sidebar has two project actions: + +- **Add new project** opens an existing working project or a portable copy someone + gave you. Selecting a prepared copy checks its inventory and opens the restore + form automatically; choose a new local project folder, restore, then open it. +- **Start a brand new project** asks for a name and an empty folder and creates + the project manifests and managed storage. Opening initializes its database. + New project asks for a name and one **Project folder**. That exact folder is the project root: it can be anywhere writable, outside the application code. Choose a new or empty folder; existing project folders should be opened instead. No extra parent workspace or generated subfolder is required. +For example, name a new project **Spike response study** and choose a new or +empty folder named **Spike response study** in your own research location. +Matching names make the folder easier to recognize later. The project name is +shown in the app; the folder name can differ, and neither name is its unique +identity. A project's name can change without moving its files. + +When reopening or receiving that project, select the **Spike response study** +folder itself. Its project files and contents should be directly inside it. +Choose its top folder rather than the research folder above it or an `imports`, +`database` or other folder inside it. The app checks the files to identify the +project, so a renamed folder can still be recognized. + Open project checks the identity manifests, storage layout and database files before starting the project, then checks recording dependencies during opening. It opens the folder in place. The preferred projects location is optional. +Created, restored and successfully opened project roots are remembered in a +local user-profile index, so projects on other drives or outside the preferred +location remain in the chooser after closing or restarting. The index contains +folder references and display identities; the project files stay in their +chosen location. An unavailable drive leaves an unavailable project entry. + +Choose the top folder containing `project.json` and `catalog.json`, or the top +folder of a received portable copy. If you choose a project subfolder, the app +suggests its nearest valid project root. If you choose a parent, it lists valid +immediate child roots. Select **Use this folder**, then open or check that folder. +Several matches remain separate choices; the app does not open one automatically. +Nearby-folder discovery is bounded and read-only; it does not scan a whole drive. + To organize a closed native project, expand **Optional: move to a preferred location**, select **Move this folder before opening**, and review the new exact destination. The app moves the whole folder without overwriting an existing @@ -19,24 +66,31 @@ disk, close the project, copy its whole folder with the file manager, and open t copy before removing the old folder. -## Automatic update notifications +## Automatic update availability Rieke OS checks the official GitHub release channel when you open the app, every 15 minutes while the page is visible, and when you return after that interval. -No button press is required. A newer release produces an **Update available** -notice in the app and an update indicator in the header. Dismissing the notice -leaves the header indicator available. - -The header distinguishes **Up to date**, **No release published**, and **Update -check unavailable**. An offline check does not count as up to date. Open the -indicator for installed version, last check, release notes, and an optional manual -retry. Manual retries bypass the automatic check cache. - -Managed installations with the official trusted signing key can download and -verify a release from this panel. The download prepares a separate installation; -it does not replace the running app or modify projects. After staging, follow the -displayed apply command. Activation waits for project services to close and -refuses incompatible database versions. Automatic shutdown/restart from the +No button press is required. A newer release highlights **Release / Publish** +with a persistent **Update** badge in the project sidebar and project chooser. +There is no toast, system notification, or automatically opened dialog. Opening +and closing the panel leaves the badge available until a successful check shows +there is no newer release. + +Open **Release / Publish** for installed version, last check, release notes, and +an optional manual retry. The panel distinguishes **Up to date**, **No release +published**, and **Update check unavailable**. An offline check does not count as +up to date or erase an update already discovered during this app-service session; +the panel explains when a refresh failed. Manual retries bypass the automatic +check cache. + +Managed installations with the official trusted signing key automatically +download and verify a new release in the background. The download prepares a +separate installation; it does not replace the running app or modify projects. +The badge changes to **Ready** once preparation completes. Close Rieke OS and all +project services, then launch normally through the stable manager or a workspace +launcher created by the managed app. That launch applies the prepared update. +If another service is still open, the current version continues to run. +Incompatible database versions are refused. Automatic shutdown/restart from the browser is not implemented. Development checkouts can check for releases but cannot install them in place. @@ -44,6 +98,10 @@ No signed release or trusted production key has been published by this change. Release workflows and signing setup must be configured before downloads become available to users. +MATLAB is optional: the app runs without it. Only opening the EpicTreeGUI export +in MATLAB needs a MATLAB installation. The self-contained desktop installer is +still release-engineering work; the current source bundle requires setup tools. + ## Open, move, or share a project folder The main project catalog and user state remain MySQL/DataJoint. New projects use @@ -82,9 +140,25 @@ interchange. **Prepare to share** remains available when you want a separately verified copy with a logical database backup and all registered recordings included. It tests a -restore before reporting success. **Open prepared project** restores that optional -transfer to a new local folder with fresh native database credentials. Existing -projects are never overwritten. +restore before reporting success. After **Close project**, **Prepare portable +copy** opens sharing with that project's folder already selected. Give the entire +prepared folder to the recipient. Their **Add new project** action recognizes it +and restores it into a new folder with fresh native database credentials. +Existing projects are never overwritten. + +The logical backup includes all acquisition and project database tables: saved +predicates and every preset version, query run records, explorer revisions and +bindings, tags and authors, review decisions, inclusion masks, tree layouts, source +state, exports and event history. New copies record table row counts and content +checksums; restoration compares every table before updating current file paths. +Existing transfer copies without this additional database inventory remain readable. + +Recent search shortcuts and protocol pins/order are stored in +`protocols/ui-state/project-preferences.json`. The app migrates earlier browser +shortcuts when their project is opened, so these choices accompany subsequent +copies. Browser size, pane widths and the current user's author selection remain +local preferences. Durable import, app-job, error and storage history under +`logs/` is included; server process records and runtime logs are excluded. Legacy Docker projects keep their original configuration and data. They are not silently converted. Preparing a logical transfer from such a project still needs @@ -92,8 +166,8 @@ its original database available; restoring that transfer creates a native projec that no longer needs Docker. Native-to-native transfers use the bundled server and clients throughout. -The optional logical transfer currently requires an initialized project database. -Runtime logs, caches and existing backup directories are excluded from it. +Runtime logs, caches and existing backup directories are excluded from logical +transfers. Historical export files retain their original bytes; external readers of old exports may need embedded recording paths relinked. Interrupted logical restores do not resume automatically; inspect the reported destination before retrying. diff --git a/docs/design/app-icon-geometry-repair.md b/docs/design/app-icon-geometry-repair.md new file mode 100644 index 0000000..d36ba2e --- /dev/null +++ b/docs/design/app-icon-geometry-repair.md @@ -0,0 +1,7 @@ +# App icon geometry repair + +Built-in image_gen edit. Final asset: `workspace-app/public/rieke-os-icon.png`. + +## Prompt + +Correct the malformed R in this app icon. Inspect the top of the letter: there are unwanted pale diagonal wings/chevron extensions running down-left and down-right from the R's top bar parallel to the shield shoulders. REMOVE BOTH OF THESE WINGS COMPLETELY and fill their areas with matching purple. The outer shield perimeter must remain a single uninterrupted pale narrow outline. Inside the shield, draw a clearly recognizable rounded capital R: straight vertical stem on left, horizontal top bar starting exactly at the left stem and ending in the rounded right bowl, enclosed purple bowl counter, and graceful diagonal leg. The letter's top bar must NOT extend left beyond its vertical stem, and must NOT extend right beyond its rounded bowl. NO diagonal shoulders or chevrons on the letter's top. A clean purple gap must separate the complete top of the R from the outer shield border, and purple must also separate the R's upper left and upper right from the shield shoulders. Preserve the R's sweeping leg and purple negative space underneath, existing muted lavender/plum palette, rounded square tile, soft matte layered rim, transparent exterior. Keep the overall shield size and composition. This is a targeted geometry repair, no new decorative lines, no double shield, no inner chevron, no additional symbols. One finished app icon. diff --git a/docs/design/app-icon-shadow-cleanup.md b/docs/design/app-icon-shadow-cleanup.md new file mode 100644 index 0000000..176ef65 --- /dev/null +++ b/docs/design/app-icon-shadow-cleanup.md @@ -0,0 +1,7 @@ +# Shadow cleanup + +Edited with built-in image_gen. Final asset: `workspace-app/public/rieke-os-icon.png`. + +## Prompt + +Targeted cleanup of this exact R shield app icon. Remove the ugly nearly black/plum offset shadow wedges around the letter, especially below the upper-left junction and around the lower-right junction where the diagonal R leg meets the shield. Remove ALL dark extruded outlines/drop shadows immediately surrounding the pale R and pale shield. Exposed negative spaces should reveal a consistent muted lavender tile face, not near-black triangular pockets or heavy dark borders. Keep the pale R silhouette EXACTLY: separate straight top bar, round bowl, left stem, sweeping leg. Keep the pale single shield outline and purple empty area beneath R. Keep a clear lavender separation between R top bar and shield top. Preserve original rounded square tile and outer layered rim unchanged; ONLY clean the central emblem's dark outlines and shadow artifacts. Result is a clean flat pale lavender R and shield on a consistent mid-purple face, with precise smooth edges and no dark wedges, no extruded side faces, no black spots. No redesign or side extensions. Transparent outside rounded tile. diff --git a/docs/design/app-icon-top-bar.md b/docs/design/app-icon-top-bar.md new file mode 100644 index 0000000..74c90de --- /dev/null +++ b/docs/design/app-icon-top-bar.md @@ -0,0 +1,7 @@ +# Top bar refinement + +Generated with built-in image_gen. Saved to `workspace-app/public/rieke-os-icon.png` and used by the sidebar and browser icon. + +## Prompt + +Make one precise edit to this purple R shield app icon. The pale top horizontal stroke of the R currently merges into the pale top border of the shield. Separate them: draw a clearly visible continuous purple negative-space horizontal gap between the shield's top inner edge and the R's own top bar. The R must have its OWN distinct rounded horizontal top bar that flows into its rounded right bowl, sitting below the shield top border. Keep a thin pale shield perimeter above it. Gap must be bold enough to remain visible at 38px icon size (roughly 35-45px high on this 1254px canvas). The R stays a connected recognizable pale R with rounded corners, stem and sweeping diagonal leg. Preserve purple negative space beneath R. Preserve all other styling, muted lavender and plum palette, rounded-square tile, rim, scale and transparent exterior. Do not add a bar above the shield. No text, no mockup. Output the corrected single icon. diff --git a/docs/design/app-icon.md b/docs/design/app-icon.md new file mode 100644 index 0000000..ab38c97 --- /dev/null +++ b/docs/design/app-icon.md @@ -0,0 +1,13 @@ +# Rieke OS app icon + +Asset: `workspace-app/public/rieke-os-icon.png` + +Generated with the built-in image_gen tool using the three user-supplied references (R shield, rounded blue icon style, purple sidebar palette). + +## Generation prompt + +Create one production app icon for Rieke OS. Reference 1 is the subject: preserve recognizable stylized R inside pentagonal diamond superhero shield. Reference 2 is style only: rounded square tile, thick layered inset border, restrained smooth gradient and dimensional offset relief. Reference 3 is palette/context only: muted lavender and deep aubergine sidebar. Make a purple rounded square tile with deep plum outer rim, lavender inner rim, violet-to-plum face, and a large high contrast pale lavender/ivory R shield emblem centered. Preserve the R with its broad curved upper bowl and diagonal leg, and its shield silhouette. Replace all red/yellow/blue with harmonious purples. Clean precise vector-like edges, bold simple legibility at 36px, minimal layers, no glossy sparkle, no text beyond the R, no additional symbols. Single straight-on square icon, almost fills canvas with only 2% transparent outer padding, genuinely transparent outside rounded corners. No mockup, no multiple versions, no background. + +## Final refinement prompt (built-in image_gen) + +Refine the app icon in reference 1 to belong to the actual UI in reference 2. Reference 3 shows the original custom R superhero shield identity. Final single production square icon with transparent outside rounded tile. Critical requirements: all enclosed negative space UNDER the R must be PURPLE tile background, NEVER white fill. The R should have rounded flowing sculpted curves like the fluid S in Superman's shield, but unmistakably an R, with rounded bowl, softened corners, and a gracefully sweeping curved diagonal leg. Keep leg and stem bold enough at 38px. The app visual language is quiet, warm, muted lavender #baa4ce, dusty lilac #d9cce4, aubergine #302538 and soft purple #685275. Use these subdued colors, no saturated electric violet. Rounded-square tile with a subtle two-layer inset rim inspired by the original blue app-icon reference, but reduce visual weight: soft matte lavender face, delicate slightly lighter top edge, darker plum lower rim. Central shield/R symbol in rich dark plum, lighter dusty lavender negative spaces matching tile. Narrow shield border with softened shoulder corners and softened bottom tip. Rounded R with broad curving strokes, no razor-sharp hooks. Whole icon feels like a beautifully crafted member of the existing app theme, restrained gentle depth, near-flat smooth colors. No glossy 3D bevel, no dramatic shadow, no texture, no grain. Central R shield as large and readable as possible with sensible breathing room. Single icon, straight-on, 2 percent transparent padding, no mockups, no explanatory text. diff --git a/docs/design/electron-production-spec.md b/docs/design/electron-production-spec.md new file mode 100644 index 0000000..1062a56 --- /dev/null +++ b/docs/design/electron-production-spec.md @@ -0,0 +1,261 @@ +# Rieke OS Electron production specification + +Status: implementation specification, 2026-09-29. Electron is the selected +desktop direction following the user's preference. This specification replaces +the AppKit/Sparkle proposal in the [earlier installer plan](one-click-installer.md). +The [GitHub comparison](../dev/GITHUB_DESKTOP_UPDATE_PATTERNS.md) remains useful +evidence about distribution mechanisms. No desktop installer is certified by +this document. + +## Product contract + +Users install a complete app from Rieke-OS GitHub Releases and open its icon. +The existing React interface runs in an Electron window. All required Python, +parser utilities, database executables and frontend assets are bundled. First +launch and ordinary use require no dependency downloads, Terminal, system Python, +Node, Git, compiler, Homebrew, Docker, or MATLAB. Original recordings and projects +are kept outside the app and are never part of an application update. + +New versions are checked automatically, downloaded quietly and shown through +Release / Publish as Update or Ready. Installation waits for an orderly app quit; +the next normal launch uses the prepared version. Closing a window, an OS exit +event or an updater callback is not proof that scientific workers have stopped. +Imports and other writes must finish or explicitly cancel through their existing +transaction contracts before application replacement. + +First advertised platform: macOS Apple Silicon. Electron's cross-platform shell +does not remove backend POSIX locks/process behavior or provide an Intel/Windows +MySQL build. Support for other platforms remains a separate qualification gate. +The minimum macOS version must be determined from the complete dependency closure +and tested before release, rather than copied from Electron's minimum alone. + +Initial macOS delivery is a signed/notarized DMG containing the complete app and +the ZIP required by the updater. To retain the requested Install and Open action, +implement a first-open bootstrap mode before starting Python or any project. +That mode copies this exact complete signed app to a fixed user-owned location +such as `~/Applications/Rieke OS.app`, verifies the copied bundle, and launches +the installed copy. It must preserve permissions, symlinks and signatures, handle +an existing installation safely, and not overwrite a running app. Normal download +and macOS first-open prompts still apply. This install action remains E06 work; +electron-builder's DMG creation alone does not implement it. + +## Intended infrastructure + +| Component | Intended responsibility | Current gap | +| --- | --- | --- | +| Rieke-OS public repository | Canonical reviewed application baseline, release tags, documentation and version history | New development behavior lives in a separate dirty epicTreeGUI checkout. Reconcile deliberately. | +| GitHub Actions | Build dependencies and frontend, run tests, assemble platform artifacts, sign/notarize, qualify and publish | Public CI currently verifies source installation; no desktop pipeline exists. | +| Electron main process | Own application lifetime, launch authenticated local services, open project windows, track readiness, drain services and own updater | Not implemented. | +| Sandboxed React renderer | Existing scientific UI, draft persistence and visible update status | Current UI is a browser app; desktop bridge/navigation/download behavior needs integration. | +| Private Python runtime | Flask application served through a production WSGI server, pinned parser/wheels and compiled utilities | Existing venv and editable parser have absolute development paths. | +| Private MySQL runtime | Server/client/dump tools and complete native library/plugin closure; one database per project | Source provisioning rewrites binaries on the destination. Relocation must move into the build. | +| electron-builder | Platform installer, macOS DMG and ZIP update artifact, complete resource inclusion and update metadata | No desktop package/configuration or packaged runtime manifest yet. | +| electron-updater | Sole desktop download/install authority, configured for the public Rieke-OS GitHub provider | Source updater must be disabled for desktop installations. | +| GitHub Releases | Serve versioned installer/ZIP assets, blockmaps where generated and latest-mac.yml | Existing v0.1.2 assets are source ZIP and checksums. No separate feed service is required for this provider. | +| Signing infrastructure | Developer ID identity/private key, notarization authentication and temporary signing keychain in CI | Account ownership and protected secret configuration remain required. | +| Local user state | Preferences, service registry, diagnostics, update cache and recovery records | Must be separated from immutable application resources. | + +The desktop app must specify the GitHub owner/repository explicitly. Never ship +an Actions token, signing key or private-repository credential in the client. +Public users require no GitHub login. The RSA source manager and Sparkle appcast +are not the selected desktop protocol; electron-builder/electron-updater metadata +and macOS code-signature verification are the selected path. +[Provider contract](https://www.electron.build/docs/features/auto-update/). + +Registry versions observed on 2026-09-29 were Electron 44.5.0, electron-builder +26.15.3 and electron-updater 6.8.9. These are candidates for an exact lockfile, +not installed dependencies or compatibility-tested pins. Do not implement APIs +from newer documentation without checking the chosen package source. For example, +the documented v7 autoInstallEvent/onNextLaunch feature must not be assumed in +6.8.9 or treated as macOS behavior. + +## Resource and data ownership + +| Location | Contents and rules | +| --- | --- | +| Signed app resources | Electron main/preload, built React, standalone Python, installed dependency/parser wheels, native MySQL libraries, licenses and runtime manifest. Read-only after signing. | +| Electron userData directory | Preferences, validated process registry, app-instance identity and startup/recovery receipts. Do not store scientific catalog contents here. | +| User cache and log directories | Disposable runtime caches and bounded, redacted diagnostics; Python bytecode is disabled or redirected outside the signed app. | +| User-selected project folder | SQL data, project credentials, catalogs, H5 source references, saved queries, annotations, masks and exports. Update operations do not alter these. | + +Executables belong in electron-builder extraResources, outside ASAR. Resolve them +from process.resourcesPath, never PATH, the working directory, an editable source +checkout, or an external uv installation. The runtime manifest records app/build +version, source/parser commits, platform/architecture, Python/MySQL versions, +workspace/database compatibility and packaged resource hashes. The manifest is +covered by the signed app; an untrusted metadata file alone cannot authorize +execution or a project migration. + +Parser configuration must support a user-state location. Its current generated +config.ini inside the source package and bootstrap origin probe must be adapted +for installed wheels. Preserve parser semantics and run source-fidelity checks +after that change. Build native binaries and finish dependency-path rewrites +before signing; no first-launch pip/conda setup or ad-hoc re-signing is allowed. + +## Reliability requirements and acceptance evidence + +These are release requirements, not claims about present behavior. + +| ID | Required invariant | Evidence that closes it | +| --- | --- | --- | +| R01 | Project ownership, original H5 identity/checksums and scientific state survive installation and updates. | Real import/tag/query/export/restart and source-user migration comparisons before/after. | +| R02 | The artifact is self-contained and relocatable, with no operational reference to build-user directories or external dependencies. | Offline install/use under another standard user and path; packaged import and native dependency audit. | +| R03 | Startup exposes the scientific UI only after the exact owned app/service versions are ready. | Wrong version, occupied port, failed import and duplicate-launch fault tests. | +| R04 | Exactly one process owns desktop installation; renderers and Python APIs cannot independently install or restart code. | IPC/API authorization tests and a concurrent two-window update test. | +| R05 | Active writers are never killed to install an update. | Imports, inbox ingestion, transfers and exports hold the update pending; every owned service acknowledges drain/exit. | +| R06 | Network, metadata, signature, platform, interrupted-download and disk failures leave the current app usable. | Fault injection against real packaged update clients, including restart after interruption. | +| R07 | The signed bundle is unchanged after launch, import, export and shutdown. | Signature verification and resource hashes before/after on downloaded artifacts. | +| R08 | Incompatible workspace/database/MySQL formats never silently activate or downgrade. | Reject incompatible packaged candidates before installation; separately validate any future migration. | +| R09 | A failed new backend/renderer startup reaches a recovery UI before opening or modifying projects. | Deliberately broken new-version health test and recovery using the last compatible signed artifact. | +| R10 | Release promotion never points clients at partial, missing, mismatched or older assets. | Multi-job publication/retry/race tests and verification of final public URLs/hashes. | +| R11 | Renderer content has no general filesystem, shell, process or updater authority. | Isolation/sandbox/CSP/navigation/IPC tests against malformed messages and foreign frames. | +| R12 | Diagnostics support recovery without leaking credentials or scientific recordings into release artifacts. | Logs/receipt redaction, packaging inventory and reproducible failure reports. | + +Normal startup has a bounded readiness deadline with explicit failure information; +choose the production timeout from measured cold/warm launches on the supported +hardware. Backend request draining currently has a 30-second deadline. Reaching +any drain deadline defers replacement and keeps recovery controls available; it +does not authorize force-killing a writer. A process crash and OS shutdown need +their own recovery tests, since Electron quit hooks are not universal shutdown +acknowledgements. + +## Desktop service and renderer boundary + +Electron starts only its bundled interpreter and registered application entry +points, passing private session identity and user-state paths. Python binds +loopback only, with host/origin checks and a per-launch capability for desktop +control. Credentials and capabilities are not sent to external pages or logs. +Validate process records by PID plus executable/release, project identity and +physical path; PID existence alone is insufficient after a crash or PID reuse. + +Initial integration may load the owned loopback UI to retain existing same-origin +API behavior. Before release, test server impersonation and desktop capability +handling; localhost is not an authentication mechanism. Use contextIsolation, +renderer sandboxing and nodeIntegration disabled, restrictive CSP, blocked +arbitrary navigation/popups and narrowly validated IPC. Open approved HTTPS +release notes externally with no privileged bridge. File chooser/download +integration must preserve the existing project path validation. +[Electron security requirements](https://www.electronjs.org/docs/latest/tutorial/security). + +The preload bridge exposes typed operations and serialized status, not raw +ipcRenderer, arbitrary URLs, shell commands or filesystem paths for execution. +Validate sender window/frame and payload on every privileged operation. +Draft persistence is acknowledged before orderly closure. A renderer crash must +not imply permission to kill its backend or discard a job. + +## Update state machine + +```mermaid +stateDiagram-v2 + Current --> Checking + Checking --> Available: compatible published version + Checking --> Current: confirmed current + Checking --> Deferred: network or metadata failure + Available --> Downloading + Downloading --> Validating: complete cached artifact + Downloading --> Deferred: interrupted or failed + Validating --> Ready: signature and compatibility pass + Validating --> Deferred: invalid or incompatible + Ready --> Draining: orderly quit requested + Draining --> Ready: busy or unacknowledged service + Draining --> Installing: all writers and services closed + Installing --> HealthCheck: native updater relaunch + HealthCheck --> Current: packaged health verified + HealthCheck --> Recovery: startup failed +``` + +The main process publishes these states to all windows. Status survives normal +restart where appropriate, and failed refresh does not erase a verified pending +update. Configure automatic downloads and an hourly check with jitter; do not +call a system-notification convenience API. A manual check remains available. +Retries are bounded and distinguish transient failures from rejected artifacts. + +For the candidate electron-updater 6.8.9, explicitly set autoInstallOnAppQuit=false +and leave downgrade/prerelease selection disabled for stable clients. Only our +coordinator may call quitAndInstall, after package validation and all drain +acknowledgements. Native Squirrel.Mac staging can occur later than the library's +downloaded event; the Ready badge must not imply a signature/health guarantee +that has not been established. Implement a candidate-validation step with exact +expected app identity, platform, version and compatibility, and qualify it using +the pinned updater's actual macOS behavior. +[Pinned updater control](https://github.com/electron-userland/electron-builder/blob/electron-updater%406.8.9/packages/electron-updater/src/MacUpdater.ts). + +Do not call quitAndInstall first and rely on before-quit to save drafts: Electron +documents that this path closes windows before that event. All preparation must +precede the native installer call. Ordinary close, Quit, OS session-end and +installer-triggered quit require separate tests. +[Electron quit ordering](https://www.electronjs.org/docs/latest/api/app#event-before-quit). + +Rollback is not assumed from updater library selection. Retaining a signed prior +installer and providing a recovery path without opening projects are required +work. Recovery must verify app/data compatibility and use the same controlled +installation boundary; it must not become a second arbitrary-code updater. + +## Release pipeline and controls + +In Rieke-OS, a reviewed version tag triggers the platform build. Build from a +clean source baseline with exact JS/Python/native pins, compare all version and +compatibility declarations, assemble resources, sign nested binaries/app, +notarize and package final DMG/ZIP assets. Generate latest-mac.yml and hashes for +the final bytes. Never sign an intermediate archive and mutate it afterward. + +Test both ordinary installation and an actual older-to-newer update using the +exact artifacts destined for publication. Assemble a draft release until all +required assets and evidence are present. Serialize promotion across versions, +verify public artifact availability and updater metadata, and only then mark the +complete release stable/latest. No raw-branch appcast or additional update +service is needed with the selected electron-updater GitHub provider. + +Configure least-privilege build/publication jobs and protected signing secrets; +ordinary PRs do not receive them. Reviewer protection must be explicitly enabled +where used. Cache dependencies for speed but validate pins/hashes; a cache hit is +not provenance. Retrying a release recovers the original artifact hashes rather +than silently replacing public bytes. Stable and prerelease channels are +explicitly separate. A withdrawn or incompatible release does not force users +off a still-working installation. + +Each release evidence bundle records source/build versions, artifact hashes, +platform/OS/architecture, packaged dependency inventory/licenses, signing and +notarization results, fresh-install results, old-to-new results, native database +restart/backup/restore and independent-client fault scenarios. Do not publish +private recordings, local paths, database credentials or signing material. + +## Implementation gaps and build sequence + +| Work | Scope | Current status | Depends on | +| --- | --- | --- | --- | +| E01 | Reconcile reviewed public/development baseline and coordinated release version | Open; no source sync or release bump performed | None | +| E02 | Build portable Python/wheels and relocated MySQL closure | Open; source runtime preflight is the first executable audit | E01 | +| E03 | Externalize mutable state and implement signed runtime manifest/readiness contract | Open | E02 | +| E04 | Electron package/main/preload, isolated renderer, owned backend supervision and production WSGI serving | Open | E02, E03 | +| E05 | Global service registry, draft acknowledgements and drain/quit/crash recovery | Open; project-specific close is useful but incomplete | E04 | +| E06 | electron-builder self-contained DMG/ZIP resources and first-open Install and Open mode | Open | E02–E04 | +| E07 | Candidate validation, quiet update state, controlled installation and recovery | Open; source updater is not this desktop implementation | E05, E06 | +| E08 | Developer ID/notarization configuration and signed platform qualification | Open; signing owner/secrets needed | E06 | +| E09 | GitHub desktop release workflow, complete promotion and metadata | Open; source-candidate workflow cannot substitute | E07, E08 | +| E10 | Source-user migration and clean-machine, multi-client, failure-injection qualification | Open | E05–E09 | +| E11 | Intel/Windows/Linux backend support and independent native artifacts | Outside first advertised scope; POSIX/runtime gaps remain | Platform decision and dedicated evidence | + +Execute in that order. E02/E03 are the largest immediate packaging unknowns; +resolve them before declaring an installer ready. Unit tests support individual +contracts. Production acceptance also requires real clean-machine installation, +real native database/scientific workflows and a real signed update. No count of +passing mock tests closes those gates. + +## First implementation receipt + +The first bounded implementation is a read-only source-runtime preflight: +[desktop_runtime_audit.py](../../tools/desktop_runtime_audit.py). It checks known +external interpreter/venv/editable/configuration paths and source provenance, +and records actionable blockers. It does not execute project code, start SQL, +package an app, validate all dynamic libraries or certify production readiness. +Its findings feed E02/E03; portable-runtime assembly and relocation remain open. + +The first [local preflight receipt](../dev/desktop-runtime-preflight.json) is +blocked as expected: seven findings identify an external Python interpreter +(including its three executable links), an absolute venv home, the editable +parser import path and instance-specific parser configuration. The auditor +inspected 3 Python path files and 3,049 runtime symlinks. Six fault tests pass, +including rejection of external/escaping paths and malformed metadata and the +requirement that even a clean static result never claim production qualification. +This is baseline evidence, not a relocated-runtime pass or Electron build. diff --git a/docs/design/external-tag-return.md b/docs/design/external-tag-return.md new file mode 100644 index 0000000..985a314 --- /dev/null +++ b/docs/design/external-tag-return.md @@ -0,0 +1,75 @@ +# Automatic external tag return + +Status: initial receiving path implemented. Implementation details below supersede the earlier proposal where noted. + +## Decision + +Keep shared project annotations as the authoritative tag store. The receiving service scans registered export folders for external tag additions. Each export carries its own writable annotation return area beside its frozen database. No separate project inbox location needs to be supplied to Wheeler, and the user never reimports the dataset. + +```text +project/exports// + recordings.sqlite frozen recording metadata + annotation-return.json format, identities, relative return path + annotations/ + incoming/.json + receipts/.json +``` + +Wheeler reads the exported database, obtains exact epoch/cell UUIDs, and writes a tag message into that export's `annotations/incoming` directory. The project service discovers it, commits tags to the existing DataJoint annotation store, and updates the UI. A helper can make this a single `tag(target_uuid, tag, author)` operation for any external service; implemented by `workspace_external_tags.submit_tags` and its CLI. + +The SQLite file remains a frozen scientific handoff. Its current annotation tables are export-time snapshots, protected by mutation triggers; the export download route also verifies the saved artifact checksum. Modifying that file would invalidate the artifact check. A writable sidecar therefore gives the actor a place to tag the exported data while preserving the existing export contract. The sidecar can be attached to SQLite for analysis if needed, but JSON additions are sufficient for the initial receiver. Do not scan arbitrary changes in frozen tag tables or import the old snapshot as new assertions. + +## Receiving-end experience + +- Opening a project page automatically POSTs a scan of its registered export return directories. +- Reloading the page scans again. The External tags control also offers Check for tags and shows scan state. +- While a project page is visible, a sequential three-second poll picks up additions without user action; returning to the page checks immediately. Scan bounded return directories, not all recordings or arbitrary SQL files; a filesystem watcher can reduce latency but is not the correctness mechanism. +- The epoch's ordinary Tags area gains the tag with Wheeler attribution. Existing direct/inherited scope and query fields remain in use. A publication-specific count of tagged child epochs is a future UI extension. +- Existing tag search and author filters work after ingestion. The External tags control shows a received count; expanding it shows recent authors, counts, and receipt times. Normal success does not open a dialog. +- The External tags control lists each return location, last checked time, pending/error count, and a “Check for tags” retry. Missing folders are shown as unavailable, never interpreted as tag deletions. + +Only a folder visible to the receiving machine can be scanned. The default is the app-managed export folder Wheeler opens in place. If Wheeler works on a copy elsewhere, deliver/synchronize its complete annotation messages into the original project export return folder. Registering arbitrary alternate folders is not implemented. A remote copy cannot communicate changes without a shared path, file transfer, or API. Do not synchronize a live writable SQLite database through a file-sync service; complete immutable JSON messages work better for that case. + +## What already exists + +- `python/workspace_annotations.py`: project-scoped `SharedAnnotation` records keyed by target kind, target UUID, and author profile UUID; revisions, locking, transactional audit, batch reads, and tag suggestions. +- `python/workspace_tag_exchange.py`: portable `rieke-tag-exchange` v1 JSON; exact UUID/source checks; additive import preview/apply; author attribution. Repeated additions do not duplicate tags. +- `python/workspace_sqlite.py`: exported `epoch_uuid`, `cell_uuid`, `project_uuid`, `export_uuid`, and source hashes; frozen `shared_annotations` and `annotation_revisions`. Exported `epoch_tags` instead means protocol curation. +- `python/workspace_tag_predicates.py`: query fields for direct cell tags, direct epoch tags, effective tags, and authors. +- Web components already distinguish direct epoch tags from inherited cell tags. UI saves invoke local refresh callbacks. There is no project-wide external annotation change observer in the inspected frontend. + +Today a service can use the existing HTTP preview/apply endpoints, but the portable-file workflow requires explicit import and the open UI has no automatic notification path. + +## Implemented transaction and discovery + +Both SQLite export paths create `annotation-return.json` and `annotations/incoming`. Existing registered SQLite exports receive these sidecars on first scan. The manifest lists exact targets and source hashes and supplies a message example; it is a convenience for writers, not the receiver's authority. The receiver validates membership against the database's registered export recipe and current acquisition identity registry. + +Writers publish uniquely named complete JSON messages using an atomic rename or the provided helper (which uses a temporary file and an exclusive hard link). Each message contains a fresh UUID, export UUID, and an existing v1 tag-exchange document. All entries must name this project and provide matching source evidence. Profile names are attribution claims consistent with the existing local model; no authenticated remote actor boundary is implied. + +`POST /api/annotations/scan` runs under the existing HTTP database lock and project annotation lock. It visits registered export folders only, rejects redirected folders/message symlinks, limits messages to 8 MiB, rotates through at most 100 messages per export per scan, and uses the existing bounded tag validation. Malformed messages report per-file errors without blocking other valid messages. Database failures abort the request and retry on a later poll. + +Additions and a receipt are committed together by `SharedAnnotations.apply_batch`. Receipts use the existing transactional Event table, with action `external_annotation_received`, rather than introducing a second receipt database. The key is project plus message UUID; a content hash binds the entire message including its authors and export. Same ID/content returns the saved receipt; same ID/different content is rejected. Unchanged-only submissions also receive a committed receipt. The project lock serializes independent consumers. Files remain immutable and receipts are reconstructed after crashes, so deleting a file receipt cannot replay a previously removed tag. + +Imported tags are additive. Missing tags/files never delete annotations. Existing explicit author-scoped annotation edits can remove tags; automated retraction commands are not part of this initial transport. Bad identities and missing targets are reported and retried without guessing matches. + +## Implemented UI observation + +`ExternalTagSync` starts a scan when a project page opens, polls sequentially every three seconds while visible, and checks on focus. Errors back off to 30 seconds. A manual Check for tags retries immediately. There is no background daemon: closed pages resume ingestion on reopen. + +The receiver returns a compact checksum of annotation target/author revision columns. This detects changes across processes without loading tag text or requiring a schema migration. It still scans revision rows and receipt events; a persisted sequence and indexed receipt table would improve very large histories later. The response includes only the latest 20 receipts plus total counts. + +On a changed revision (including the first scan), the UI invalidates epoch resource caches and advances its existing global resource revision, refreshing tags, summaries, vocabulary, and live queries. Late monitor responses after unmount are discarded and scans never overlap within one page. This uses existing view refresh behavior rather than introducing new selection semantics. Saved query evidence, pinned snapshots, and previous exports stay frozen. + +## Scope and querying + +For publication use, tag the exact epoch UUIDs actually used, for example `publication:paper-2026-01`. Record export/run/publication provenance with the import audit. Do not automatically tag the entire cell merely because one epoch was used: a cell tag inherits to every epoch of that cell, including later imports. The cell UI can instead show a derived summary such as “3 epochs used in paper-2026-01”; that summary must not become an inherited cell tag. + +A genuine cell classification should target `cell_uuid`. It appears on that cell and as inherited metadata on its epochs across protocols. Actors can read current tags using existing `/api/annotations/read`, `/api/cells//annotations`, `/api/epochs//annotations`, and `/api/annotation-tags` endpoints, and use existing annotation predicate fields for search. Historical SQLite exports answer what was known at export time; they do not answer the current live state. + +An optional HTTP submission endpoint can later feed the same ingest function and receipt ledger. It is a second transport, not a second tag system. Avoid direct actor writes to DataJoint tables, which bypass validation, audit, receipts, and revision notifications. Automatic synchronization across separate projects is also outside this initial design: delivery names one project explicitly, even if another contains the same acquisition UUIDs. + +## Validation + +`test_workspace_external_tags.py` exercises protocol SQLite export → actor helper → scan → current annotation API and tag query, unchanged artifact checksums, cell inheritance, unchanged receipts, restart recovery, replay after removal, transactional rollback on receipt failure, invalid identity/source isolation, changed-content rejection, missing folders, and existing-export sidecar creation. Candidate export tests verify their return manifest and exact subset. + +Frontend tests cover reopen refresh, stable-revision suppression, changed revisions, overlapping scan prevention, unmount races, and error recovery. Related annotation/cache tests and the production frontend build validate integration. Automated tests use disposable database doubles and files. A subsequent live browser test used a separate native MySQL 8 instance with real DataJoint tables and transactions, the real Flask routes, and the production React build. It verified automatic epoch display and search, preserved drafts, reopen ingestion, cell inheritance, invalid-target isolation, receipt recovery from another process, replay after removal, and unchanged SQLite bytes. See `docs/dev/external_tag_live_validation.json` and `docs/dev/external-tag-live.png`. Acquisition metadata was generated for two test cells; the research database was untouched. diff --git a/docs/design/one-click-installer.md b/docs/design/one-click-installer.md new file mode 100644 index 0000000..c6b053e --- /dev/null +++ b/docs/design/one-click-installer.md @@ -0,0 +1,337 @@ +# Rieke OS one click installer plan + +Architecture status: the user has selected Electron. The +[Electron production specification](electron-production-spec.md) is now the +implementation authority. This earlier plan preserves the source audit, example +systems and initial gap analysis; its AppKit/Sparkle proposal is superseded. + +Reviewed 2026-09-29. This plan covers installation and automatic updates for the +public Rieke OS app. It is based on the current public distribution, the +development updater, and a [review of primary documentation](../dev/INSTALLER_PRIMARY_SOURCE_REVIEW.md). +It proposes implementation work; it does not claim that a desktop installer has +been built or that the proposed update path has passed validation. + +The recommended first release is a complete macOS Apple Silicon app, built on +GitHub, installed into a user-owned application directory, and updated as a whole +signed app. Users should not need Terminal, Python, Node, Git, a compiler, +Homebrew, Docker, or MATLAB. A native launcher should own all local services so +an update can wait for an orderly app shutdown. + +## Installation and update experience + +The user downloads one installer from GitHub Releases, opens it, and chooses +**Install and Open**. The proposed default destination is +`~/Applications/Rieke OS.app`, which the current user can update without needing +administrator access. The installer copies the complete app and opens it. Normal +macOS download and first-open interactions still apply; one click describes the +installer's action, not the entire download and operating-system flow. + +The app opens the existing browser interface after its local service is ready. +Projects remain in folders chosen by the user. Subsequent launches use the same +app icon. Available updates download in the background and appear in +**Release / Publish** as **Update** and then **Ready**. Ordinary updates should +produce no toast, system notification, or automatically opened dialog. When the +user quits and all workers have closed cleanly, the updater installs the prepared +version; the next launch uses it. Active scientific work must not be interrupted +to satisfy an update schedule. + +First scope assumption: Apple Silicon Macs. Intel Macs and Windows require their +own build and native integration evidence before support is advertised. MATLAB +is optional and used only to open the EpicTreeGUI export; Python writes the MAT +files and reads selection masks without running MATLAB. + +## What the inspection found + +The public repository is +[`maxwellsdm1867/Rieke-OS`](https://github.com/maxwellsdm1867/Rieke-OS). +Its inspected main commit and clean local checkout were +`f52312f06a651500ea3e121feaebd118201d0f7b`. The development checkout is the separate +epicTreeGUI repository at `47f87f9f1adc373523869ac624c35fdfe566b4e9`, with uncommitted +changes. These are different application states; development behavior is not +evidence of what public users already have. + +| Area | Published Rieke OS | Development checkout | +| --- | --- | --- | +| Release | [v0.1.2](https://github.com/maxwellsdm1867/Rieke-OS/releases/tag/v0.1.2), with a 1,463,427-byte source ZIP and SHA256SUMS | Coordinated metadata still says 0.1.0. Discovery now points to Rieke-OS. | +| Installation | [install.sh](https://github.com/maxwellsdm1867/Rieke-OS/blob/f52312f06a651500ea3e121feaebd118201d0f7b/install.sh) downloads local tooling and dependencies and compiles/builds the app | Setup likewise builds Python/parser/frontend; managed launch can use prebuilt frontend assets. | +| Launch | [start.sh](https://github.com/maxwellsdm1867/Rieke-OS/blob/f52312f06a651500ea3e121feaebd118201d0f7b/start.sh) requires a terminal and installed runtime | Python manager and chooser; no native desktop entry point. | +| Automatic updates | No updater module or signed desktop update assets | Quiet badge, automatic source staging, and next-launch activation exist locally. Staging still executes setup. | +| CI | [verify.yml](https://github.com/maxwellsdm1867/Rieke-OS/blob/f52312f06a651500ea3e121feaebd118201d0f7b/.github/workflows/verify.yml) verifies a fresh source installation | Signed source-candidate workflow and a proposed tag/publication job; these have not been carried into the public repo. | +| Release protection | GitHub API returned no configured environments and no repository Actions secret names visible to this account | No distributed trusted key in this checkout. A workflow environment name alone does not establish reviewer protection. | + +The development runtime measured approximately 1.3 GB for the Python venv, +302 MB for linked MySQL, and 45 MB for native package archives. These are local +disk measurements, not the size of a finished app or download. The interpreter +is an absolute symlink into the developer's uv installation, and the editable +parser `.pth` contains an absolute checkout path. Copying this directory would +not establish a portable app. + +## Existing GitHub distribution patterns + +GitHub can host the source, run the build, and serve the installer/update assets. +The installed application still needs a desktop updater to select its platform, +verify the downloaded package, and coordinate replacement. GitHub's automatic +Source code ZIP is not a prebuilt installer, and a successful release upload +does not by itself update users' computers. + +| Pattern | GitHub's role and client behavior | Implication for Rieke OS | +| --- | --- | --- | +| Native macOS with Sparkle | Complete app archives live in Releases; a static appcast links to exact archives/signatures. Sparkle runs in the app. | Proposed Mac-first route. GitHub can host the static feed too; no custom update server is necessary. | +| Tauri with its updater plugin | Actions builds app/update artifacts; a static `latest.json` asset in Releases supplies platform URLs and signatures. The installed plugin checks it. | Strong alternative if Windows/Linux are immediate targets. Existing React can remain the frontend and Python can be packaged as a sidecar. | +| Electron with electron-builder/electron-updater | The builder publishes installers and `latest*.yml` metadata to its GitHub provider; the app's updater reads the metadata and fetches binaries. | Established cross-platform path. Requires an Electron shell and a packaged Python/MySQL runtime; the updater does not remove backend packaging work. | +| Electron Forge with update-electron-app | Forge publishes to Releases; Electron's hosted update service translates release assets into a client feed. | GitHub-based, but uses an additional hosted service. This is a distinct route from electron-builder's direct GitHub provider. | + +Sources: [Sparkle publication](https://sparkle-project.org/documentation/), +[Tauri GitHub pipeline](https://v2.tauri.app/distribute/pipelines/github/), +[Tauri static updater](https://v2.tauri.app/plugin/updater/), +[Tauri Python sidecars](https://v2.tauri.app/develop/sidecar/), +[electron-builder updater](https://github.com/electron-userland/electron-builder/blob/master/website/docs/features/auto-update.md), +[Electron Forge publishing tutorial](https://www.electronjs.org/docs/latest/tutorial/tutorial-publishing-updating). + +Rectangle and MonitorControl are directly verified native Mac examples. Their +app configurations embed Sparkle feed URLs and EdDSA public keys, and their live +feeds point to signed version-specific DMGs in GitHub Releases. +[Rectangle configuration](https://github.com/rxhanson/Rectangle/blob/c0ae7f87abe66f66b2857fbd4ad19ef802a9b43a/Rectangle/Info.plist), +[Rectangle feed](https://rectangleapp.com/downloads/updates.xml), +[MonitorControl configuration](https://github.com/MonitorControl/MonitorControl/blob/84ac2d72bfb53b653536e484946f6ed027e4229c/MonitorControl/Info.plist), +[MonitorControl feed](https://monitorcontrol.app/appcast2.xml). +These examples show GitHub serving app binaries while separate static URLs serve +update metadata. Rieke OS can host its static feed on GitHub too. The inspected +Rectangle public build workflow only produces an ad-hoc signed Actions artifact; +it does not establish how its production signing/publication is automated. + +One directly inspected application is Electron Fiddle. Its +[Forge configuration](https://github.com/electron/fiddle/blob/a63225b53664fd750828c29aa35de4b4d0eb0b28/forge.config.ts) +publishes to `electron/fiddle` on GitHub, and its +[updater code](https://github.com/electron/fiddle/blob/a63225b53664fd750828c29aa35de4b4d0eb0b28/src/main/update.ts) +starts `update-electron-app` after a startup delay, configured for hourly checks. +That demonstrates the connection between a release publisher and installed +clients; it does not establish that Fiddle's notification or shutdown behavior +matches our quiet-update and scientific-worker requirements. + +Use an existing framework's artifact generator, metadata format, signature +verification and installer. Build our own app/service lifecycle adapter and +compatibility rules. Neither a GitHub provider nor a sidecar configuration +automatically drains our detached Python/MySQL workers, preserves browser +drafts, or qualifies a database-version change. Do not use notification-producing +sample APIs as the product behavior when routine updates should stay quiet. + +The desktop shell decision is conditional on platforms: AppKit/Sparkle is the +recommended first route for the current Mac-first scope. If Windows must ship +alongside macOS, evaluate Tauri before implementing I05 and I08. Electron is an +alternative when its Chromium/Node desktop environment is specifically useful. +These alternatives can reuse React and Python, but embedded webviews introduce +different origins, download/dialog behavior and process ownership that must be +tested. Framework selection does not change the I02/I03 runtime experiment. + +The [GitHub desktop update comparison](../dev/GITHUB_DESKTOP_UPDATE_PATTERNS.md) +records the exact application sources, feed examples, and framework contracts. + +## Proposed architecture + +Use a small Swift/AppKit application to provide the app icon, launch readiness, +duplicate-launch handling, Quit, service ownership, and updater integration. +Keep React as the product interface in the browser. This does not require +rewriting the scientific application in Swift or adding Electron. + +Bundle a pinned standalone Python interpreter, installed dependency wheels, +the pinned parser and compiled utilities, built React assets, and a relocatable +private MySQL server/client/dump dependency closure. Complete binary relocation +and configuration of executable paths during the build. Sign the final code, +notarize the product, and leave its contents read-only at runtime. Apple's +signature seals the app's resources and nested code; current destination-side +conda linking and ad-hoc signing cannot be used inside that sealed product. +[Apple code-signing rules](https://developer.apple.com/library/archive/technotes/tn2206/_index.html). + +Proposed ownership layout: + +```text +~/Applications/Rieke OS.app/ signed code and immutable resources +~/Library/Application Support/RiekeOS/ preferences, service registry, update state +~/Library/Caches/RiekeOS/ disposable runtime caches +~/Library/Logs/RiekeOS/ application and installer diagnostics +/ catalog, SQL data, credentials, H5 references, exports +``` + +The native launcher resolves resources from its actual bundle location and +invokes its bundled interpreter by absolute path. Python bytecode, parser +configuration and temporary files must go outside the bundle or be disabled. +`doctor` validates the packaged layout and signed build receipts, rather than +requiring a Git checkout, editable package location, or Node installation. + +The default packaging approach is a standalone interpreter with preinstalled +packages and a parser wheel. PyInstaller `onedir` workers are a fallback to +evaluate if that layout fails; a choice between these approaches must be based +on the relocation/import experiment, not an assumption that either handles +dynamic parser imports and native MySQL automatically. + +### One desktop updater + +**Recommendation:** use Sparkle for complete signed app updates. The native app +owns update state; React displays it through a local bridge. Disable the Python +manager's staging/activation routes in desktop builds. Its useful existing +tests become requirements for the new path, not proof that Sparkle preserves +those behaviors automatically. Source installations may retain a separate +explicitly identified updater if we choose to support them. + +This changes the earlier source-updater direction: a shipped app should download +prebuilt software, not run `rieke.py setup` on the user's computer. The current +manager also lacks an independent bundled bootstrap interpreter, uses an RSA +manifest instead of Sparkle's EdDSA/appcast contract, reads downloads into memory, +limits artifacts to 512 MiB/extraction to 2 GiB, and rejects every symbolic link. +That extractor is unsuitable for a normal Sparkle framework bundle, whose +symlinks and executable permissions must be preserved. +[Current manager](../../python/workspace_updates.py), +[Sparkle setup](https://sparkle-project.org/documentation/). + +Sparkle's automatic checks and automatic downloads need explicit configuration; +they are not silent defaults. Its scheduled-check minimum is one hour. Proposed +desktop policy: a startup check when appropriate and hourly automatic checks, +with the UI text updated accordingly. The current 15-minute development watcher +must not remain as an independent download/install authority. If 15-minute +discovery becomes a hard requirement, assess that separately before committing +to this updater policy. +[Sparkle customization](https://sparkle-project.org/documentation/customization/). + +Keep ordinary updates pending until orderly app quit, including the framework's +impatient-update behavior. A custom Sparkle user driver cannot merely hide all +UI: automatic-update settings provide silent installation, and manual actions +or necessary authorization still need a conforming interface. A user-owned app +location reduces authorization requirements; managed Macs may impose other +policies. Verify these cases in the product rather than promise that all updates +can always be invisible. +[Sparkle user-interface contract](https://sparkle-project.org/documentation/custom-user-interfaces/). + +## Gap map and implementation order + +All entries below are open for the desktop product, even where a useful source +implementation exists. IDs are implementation work packages, not filed issues. + +| ID | Gap and concrete work | Depends on | Completion evidence | +| --- | --- | --- | --- | +| I01 | Establish Rieke-OS as the public build authority; selectively reconcile the development changes and coordinate app, npm, bundle and tag versions. | None | A clean reviewed public commit reproduces the chosen feature baseline and version checks. No wholesale replacement of the independently validated public app. | +| I02 | Build a portable Python layout and noneditable parser wheel; include compiled utilities and data files; adapt parser configuration and readiness probes. | I01 | Copy to a different user/path and run all imports/parser work offline with no external interpreter or checkout. | +| I03 | Prepare the complete private MySQL runtime in CI; resolve runtime load paths, plugins, TLS/share resources and licenses before signing. | I01 | Server/client/dump, actual import and dump/restore work after relocation, with no system MySQL or post-install code rewriting. | +| I04 | Move all mutable preferences, caches, compatibility configuration and receipts out of app code. Preserve user-selected project locations. | I02, I03 | Read-only app works; launch, imports and quit leave its signature valid. | +| I05 | Add native lifetime owner, readiness checks, occupied-port handling and a bundled production WSGI server on loopback; retain project origins where possible. | I02, I04 | Double-click launch reaches the UI once; duplicate launch reuses the right instance; failures are visible without Terminal. | +| I06 | Coordinate every chooser/project service, inbox/import, export/transfer and database during Quit; preserve browser drafts and acknowledge shutdown. | I05 | Busy work defers Quit/update; all admitted requests drain and all owned databases close cleanly before native termination. | +| I07 | Package the complete app and a small Install and Open helper into a downloadable installer. Copy to a permanent user-owned location without downloading dependencies. | I03–I05 | Fresh standard user installs offline using the native action and launches without developer tools. | +| I08 | Integrate Sparkle as the sole desktop updater, signed appcast, compatibility filtering and React Update/Ready state. | I05, I06 | Real older app downloads a complete update quietly; it stays pending during work and installs only after safe quit. | +| I09 | Configure Developer ID signing, hardened runtime, notarization and Sparkle EdDSA signing; verify the complete nested-code closure. | I02–I07 | Browser-downloaded artifact passes Gatekeeper/notarization checks and still verifies after real use. | +| I10 | Replace the source-candidate publication path with a prebuilt desktop pipeline; publish versioned assets before advertising them in the stable feed. | I08, I09 | Tag produces the exact tested/notarized installer and update archive; failed jobs never advance the stable feed. | +| I11 | Provide crash/startup recovery and previous-version restoration within the same updater authority. Port database-generation restrictions. | I06, I08 | Failed new startup can recover without losing data; incompatible schema or MySQL formats never silently activate or downgrade. | +| I12 | Migrate existing v0.1.2 source users through one explicit desktop install, preserving projects/preferences and retiring old launch paths safely. | I06–I08, I11 | A real existing project reopens with the same source references, tags, queries and export history after old services stop. | +| I13 | Run the full clean-machine and multiple-client qualification below, then publish the installer. | I07–I12 | Recorded passing evidence for the actual final artifact, not just a source build or mocked update. | + +Critical path: **I01 → I02/I03 → I04 → I05/I06 → I07/I08 → I09/I10 → I11/I12 → I13**. +Signing account preparation can start earlier, but final code is signed only +after relocation and bundle assembly. Recovery and compatibility design should +be specified before I08, even though their full tests depend on it. + +### Why shutdown is a first release requirement + +The development [project lifecycle](../../python/workspace_lifecycle.py) already +drains requests and refuses closure while imports are active. Extend that +contract to every service and work type, and make the native app own the registry +and final acknowledgement. The chooser currently has no equivalent coordinated +native Quit. Published Rieke-OS documents that Ctrl-C stops the chooser while +previously opened project services and databases may remain running. +[Published shutdown behavior](https://github.com/maxwellsdm1867/Rieke-OS/blob/f52312f06a651500ea3e121feaebd118201d0f7b/docs/RIEKE_OS_QUICK_START.md). + +Sparkle may install when the native app terminates. Therefore it is insufficient +to say an update waits until the app closes while detached workers keep using +the old runtime. Reject or postpone native termination until all workers have +acknowledged closure. After a crash, reconcile recorded processes before allowing +replacement. App file locks alone do not automatically constrain Sparkle. +[Sparkle termination contract](https://sparkle-project.org/documentation/api-reference/Protocols/SPUUpdaterDelegate.html). + +## GitHub release pipeline + +Proposed stable pipeline in Rieke-OS: + +```mermaid +flowchart LR + A[Push reviewed version tag] --> B[Tests and version checks] + B --> C[Build portable Python and MySQL] + C --> D[Assemble native app and installer] + D --> E[Sign and notarize] + E --> F[Qualify exact final artifacts] + F --> G[Publish versioned GitHub Release assets] + G --> H[Advance signed stable appcast] + H --> I[Clients download quietly] + I --> J[Install after acknowledged app quit] +``` + +Keep the source installer as a developer fallback, clearly separate from the +desktop download. A branch push runs regression CI; a stable version tag declares +release intent. No user's installed app executes `git pull` or tracks arbitrary +branch commits. + +Publish two product assets: the initial installer and a whole-app update archive +containing only the installed app. Build both from the same signed app. Generate +Sparkle signatures/appcast from the final archive bytes, after any packaging or +stapling changes. The existing RSA source manifest does not substitute for this +appcast. + +Use GitHub Release URLs for versioned binaries. Proposed feed location is a +stable HTTPS URL in the same repository, initially a raw `updates/stable` +appcast branch, updated by CI after assets exist. Validate GitHub redirects, +cache behavior, feed signatures, compatibility filtering and roll-forward +ordering with an actual client. GitHub Pages is an alternative feed host, not a +prerequisite for a separate backend service. + +The feed must never point at an unpublished/missing asset. Retrying publication +must recover the same artifact hashes, not overwrite a public release with +different bytes. Serialize promotions across versions so an older build finishing +late cannot replace the newer stable feed. No version is advertised before its +operating-system, architecture and database-compatibility checks pass. Schema +changes require a separate tested backup/migration/recovery path. + +Configure GitHub environments explicitly where approvals are wanted; the field +in a workflow does not itself enable reviewers. Credentials needed are Developer +ID certificate/private key, notarization authentication, and the Sparkle update +signing key. These are separate from the current RSA source signing key. +Keep secrets in the selected secret system, expose them only to signing jobs, +and test restoration/rotation procedures. They were not created or changed by +this planning pass. + +## Qualification before the public installer + +| Scenario | Required result | +| --- | --- | +| Clean supported Mac, standard user, no development tools, network disabled after download | Install and first project creation/import work using only the artifact and OS facilities. A GitHub runner with development tools hidden from PATH is useful, but not sufficient proof. | +| Downloaded/quarantined app, alternate user, spaces/Unicode and moved application path | Native launch, Python imports and MySQL paths work; bundle signature remains valid. No quarantine removal workaround. | +| Real original H5 and existing source-user project | Import, browse trace, tag, save query, export, restart, and dump/restore retain original identities and source checksums. Validation data is supplied separately from the app. | +| Old-to-new release on two independent clients | Both discover/download the same published version; one busy client stays on its old version while the idle client updates. Their projects/settings remain independent. | +| Active import, inbox ingestion, transfer/export, open second project and unsaved browser draft | Safe quit is postponed or drafts are preserved; no worker is killed to make an update succeed. All owned services acknowledge shutdown before installation. | +| Offline server, invalid signature, wrong platform, truncated download, disk-full and permissions failure | Current app remains usable; incomplete updates are not activated. Necessary action is available in the release panel. | +| New version fails startup or uses incompatible project/MySQL formats | Recovery restores compatible app behavior without silently migrating or downgrading data. Previous-app retention alone does not count as tested recovery. | +| No MATLAB installation | All core installation, launch, data and update scenarios pass. Optional MATLAB GUI interoperability has its own validation claim. | + +Test the exact notarized installer and archive that will be published. Preserve +machine/platform, versions, artifact hashes and pass/fail receipts. Neither the +current unit tests nor dummy-process manager tests establish these product gates. +Keep private recording data and credentials out of public release artifacts and +validation logs. + +## Decisions and next executable experiment + +Proposed defaults are Apple Silicon macOS first, a user-owned app location, +Sparkle as the sole desktop updater, hourly scheduled checks, and separate +project storage. Still decide the minimum macOS version, whether Intel/Windows +are required for the first release, who owns the signing identities, and the +publication approval policy before claiming support. + +Start with **I01 and the I02/I03 relocation experiment**, not the installer UI. +Produce a prebuilt payload from a clean reviewed application baseline, move it +to a different path, use a minimal environment with dependency downloads disabled, +and exercise real parser imports plus MySQL import/dump/restore. Record every +runtime access outside the payload and user data directories. No source venv +copy, editable install, external executable, or destination-side code rewrite +may be necessary for that pass. + +If this experiment fails, fix the packaging closure or evaluate the documented +PyInstaller fallback before building the native installer. If it passes, add the +read-only bundle configuration, lifetime owner and installer. This order turns +the largest unknown into a concrete pass/fail result before investing in the +download and launch interface. diff --git a/docs/dev/GITHUB_DESKTOP_UPDATE_PATTERNS.md b/docs/dev/GITHUB_DESKTOP_UPDATE_PATTERNS.md new file mode 100644 index 0000000..70b5cd5 --- /dev/null +++ b/docs/dev/GITHUB_DESKTOP_UPDATE_PATTERNS.md @@ -0,0 +1,135 @@ +# GitHub desktop installation and update patterns + +Reviewed 2026-09-29 against project source and official framework documentation. +Pinned commits make the inspected implementations reproducible; live feeds and +release URLs can change. These are comparative findings, not implementations +already added to Rieke OS. + +## The reusable pattern + +GitHub serves distinct jobs: source control, CI execution, downloadable Release +assets, and optionally a static update feed. The installed **client updater** +reads metadata, chooses a compatible version, verifies its artifact and controls +installation. Users do not clone/pull the source repository. A successful CI +build artifact is not automatically a public, trusted update. + +## Two concrete native macOS examples + +### Rectangle uses Sparkle and GitHub Releases + +At commit `c0ae7f87abe66f66b2857fbd4ad19ef802a9b43a`, Rectangle embeds +`https://rectangleapp.com/downloads/updates.xml` and a Sparkle EdDSA public key in +its [Info.plist](https://github.com/rxhanson/Rectangle/blob/c0ae7f87abe66f66b2857fbd4ad19ef802a9b43a/Rectangle/Info.plist). +Its native [AppDelegate](https://github.com/rxhanson/Rectangle/blob/c0ae7f87abe66f66b2857fbd4ad19ef802a9b43a/Rectangle/AppDelegate.swift) +constructs `SPUStandardUpdaterController`, exposes manual checks and supports +gentle scheduled reminders. + +The [live appcast](https://rectangleapp.com/downloads/updates.xml) contains +version/build metadata, exact file lengths and EdDSA signatures. Its current +full update points to the [v2.0.2 GitHub DMG](https://github.com/rxhanson/Rectangle/releases/tag/v2.0.2), +with optional signed deltas also hosted as Release assets. The feed host and +artifact host are independent; Sparkle does not infer metadata from a Git tag. + +Its visible [build workflow](https://github.com/rxhanson/Rectangle/blob/c0ae7f87abe66f66b2857fbd4ad19ef802a9b43a/.github/workflows/build.yml) +archives the app, signs ad-hoc, creates a DMG and uploads an Actions artifact. +It does **not** show the production Developer ID/notarization/feed-publication +pipeline. Copying that workflow alone would not reproduce its public updater. + +**Applicable lesson:** Adopt the feed-to-signed-complete-app pattern and native +update-state ownership. The existing React release panel can remain the visible +interface. Do not copy Rectangle's user-notification policy as Rieke OS's policy. + +### MonitorControl uses signed GitHub downloads and explicit channels + +At commit `84ac2d72bfb53b653536e484946f6ed027e4229c`, MonitorControl embeds +`https://monitorcontrol.app/appcast2.xml` and an EdDSA public key in its +[Info.plist](https://github.com/MonitorControl/MonitorControl/blob/84ac2d72bfb53b653536e484946f6ed027e4229c/MonitorControl/Info.plist). +Its [AppDelegate](https://github.com/MonitorControl/MonitorControl/blob/84ac2d72bfb53b653536e484946f6ed027e4229c/MonitorControl/Support/AppDelegate.swift) +creates and starts a Sparkle controller. Its +[UpdaterDelegate](https://github.com/MonitorControl/MonitorControl/blob/84ac2d72bfb53b653536e484946f6ed027e4229c/MonitorControl/Support/UpdaterDelegate.swift) +selects the beta channel only when the corresponding preference is enabled. + +The [live feed](https://monitorcontrol.app/appcast2.xml) encloses the exact +version-specific GitHub URL for the [v4.4.0 DMG](https://github.com/MonitorControl/MonitorControl/releases/tag/v4.4.0), +its EdDSA signature and length (20,391,423 bytes, matching the Release asset +observed during review). No production release workflow was present in the +inspected repository tree; publication mechanics beyond these artifacts are +not established by this inspection. + +**Applicable lesson:** Separate stable and beta selection explicitly and keep +artifact URLs bound to specific releases. Neither example implies their +application code, dependency choices or release scripts should be copied wholesale. + +## Cross-platform frameworks + +| Approach | GitHub role | Installed client mechanism | Fit for this app | +| --- | --- | --- | --- | +| Native shell + Sparkle | Releases hold signed app archives; a static host supplies appcast XML | Sparkle verifies and replaces the complete app | Evaluated native macOS alternative | +| Tauri updater | Releases hold updater archives/signatures and optionally `latest.json` | Tauri plugin checks, downloads and installs | Credible if a cross-platform webview shell becomes a requirement | +| Electron + electron-updater | GitHub provider discovers Release metadata/artifacts | electron-updater manages download/install state | Credible if Electron is otherwise wanted; it adds its own runtime | +| Electron Forge + update-electron-app | Releases hold binaries; `update.electronjs.org` supplies a feed | Electron/Squirrel consumes that service | Demonstrates GitHub-based delivery with an additional service | + +Tauri's [official updater guide](https://v2.tauri.app/plugin/updater/) documents +mandatory artifact signatures, a bundled public key and the static endpoint +`https://github.com/user/repo/releases/latest/download/latest.json`. Each +platform entry requires its artifact URL and signature. The application calls +the updater API; the existence of metadata does not define check scheduling or +safe worker shutdown. [Tauri Action](https://github.com/tauri-apps/tauri-action) +builds/publishes assets and generates that JSON. It explicitly warns that +latest-download artifact URLs can fail when other releases lack updater bundles. + +Tauri supports [external binaries](https://v2.tauri.app/develop/sidecar/), with +architecture-specific filenames. **Inference:** Python and MySQL could be +bundled sidecars while retaining React, but their portable dependency closure, +signing and orderly lifetime still require engineering. Switching to Tauri is +not necessary to solve GitHub hosting. + +[electron-builder's official update guide](https://www.electron.build/docs/features/auto-update/) +supports a GitHub Releases provider, generates internal `app-update.yml`, and +emits availability/progress/downloaded events suitable for custom UI. Automatic +download is configurable; the notification convenience API is unnecessary for +a quiet badge. macOS uses Squirrel.Mac's native staged update/relaunch behavior; +Windows/Linux installer details differ. It also requires signed macOS apps and +the corresponding ZIP update target. **Inference:** Electron could retain the +React UI and packaged Python workers, but it is a product-shell decision rather +than a prerequisite for automatic updates. + +As a real third example, Electron Fiddle at +`a63225b53664fd750828c29aa35de4b4d0eb0b28` +[publishes through Forge's GitHub publisher](https://github.com/electron/fiddle/blob/a63225b53664fd750828c29aa35de4b4d0eb0b28/forge.config.ts) +and [initializes update-electron-app](https://github.com/electron/fiddle/blob/a63225b53664fd750828c29aa35de4b4d0eb0b28/src/main/update.ts) +with `electron/fiddle`, a one-hour interval and ten-second startup delay. +[Electron's tutorial](https://www.electronjs.org/docs/latest/tutorial/updates) +explains the default `update.electronjs.org` service and restart dialog. This +is neither GitHub-only hosting nor the requested quiet UX by default. + +## Proposed GitHub deployment for Rieke OS + +Use GitHub Releases for immutable, version-specific DMG/ZIP assets. Publish the +Sparkle appcast at a stable GitHub Pages URL, or a protected branch's raw URL. +[GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/what-is-github-pages) +is a static hosting service, so a separate update server is unnecessary for this +basic channel. The raw-branch option is an engineering choice to validate, not +a guarantee of freshness or response headers. Use the raw file rather than a +GitHub HTML file view. + +GitHub [documents latest-release asset links](https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases), +but such a redirect is not an update manifest. Every promoted release must have +the correct metadata asset if using that pattern. Prefer version-specific +artifact URLs within a stable feed. Test redirects, content type, cache headers, +stale-feed responses, offline behavior and publication races from the installed +client; no promise of instant delivery follows from hosting on GitHub. + +The release sequence should be: build/relocate dependencies; sign and notarize; +package preserving symlinks; generate signatures/feed; upload all assets; verify +public URLs and signatures; publish the stable feed last. Sparkle's +[publication guide](https://sparkle-project.org/documentation/publishing/) +specifies complete app archives, symlink preservation and signature metadata. + +**Selected direction:** Following the user's preference, retain React and +Python/MySQL, add an Electron lifetime owner, and use electron-builder and +electron-updater with the direct GitHub provider. The +[production specification](../design/electron-production-spec.md) defines that +contract. This replaces the bespoke source updater for desktop activation; no +Sparkle updater runs alongside it. The largest remaining gaps are the sealed +portable runtime and worker shutdown contract, not GitHub hosting. diff --git a/docs/dev/GITHUB_TESTING_RELEASE.md b/docs/dev/GITHUB_TESTING_RELEASE.md new file mode 100644 index 0000000..0408f26 --- /dev/null +++ b/docs/dev/GITHUB_TESTING_RELEASE.md @@ -0,0 +1,45 @@ +# GitHub unsigned desktop testing releases + +The testing distribution is explicit in `desktop/distribution.json`. It uses the +public `maxwellsdm1867/Rieke-OS` repository and remains separate from Developer ID +signed production installation and updates. + +Users download the complete Apple Silicon DMG from a release asset link, open +Rieke OS, and click **Install and Open**. The app copies its complete private +runtime to the current user's Applications folder. No Terminal, Docker, Python, +Node, or external MySQL setup is required. An unsigned download may require +macOS **Privacy & Security → Open Anyway** approval before it can run. +The app has a structurally verified local ad-hoc bundle seal, which needs no +certificate and provides no Apple developer identity. The installer retains quarantine attributes and does not bypass Gatekeeper. + +In the app, **Release / Publish** displays a newer available version. Metadata +checks run at startup and about once an hour; **Check for updates** also runs on +request. A notice never starts a download. Users choose **Download update**, then +**Restart to update** once the archive and app resources have been verified. +Active imports, unsaved drafts, and scientific services can defer the restart. +An ordinary Quit does not install a testing update. + +Testing updates trust the official repository over HTTPS and compare the exact +archive, shell, runtime manifest, resource inventory, version, architecture, +macOS minimum, and database/workspace formats. These checks do not establish an +Apple Developer ID signature. The current trusted app validates the download; +downloaded Python or app code is not executed during validation. A dedicated +current-app helper waits for actual process exit, retains the prior bundle, and +installs only to the same user-owned app path. Scientific projects stay in their +selected folders. + +Each testing release includes `desktop-release.json`, the DMG, complete app ZIP, +checksums, and local qualification receipts. Its tag starts with +`desktop-test-v`, it is labeled **unsigned testing**, and it is a prerelease so it +does not replace the existing stable source release. Never overwrite published +assets under an existing version. A failed or interrupted download can be +retried; incompatible or changed candidates must remain uninstalled. + +Production signing/notarization and a clean-machine test are separate open +qualification requirements. The testing release must not be presented as a +signed production release. + +For a future signed production release, commit and review `channel: signed` in +`desktop/distribution.json` before building with signing credentials. The signed +CI job rejects the unsigned testing policy. Changing certificates alone does not +change the app’s installation/update trust policy. diff --git a/docs/dev/INSTALLER_PRIMARY_SOURCE_REVIEW.md b/docs/dev/INSTALLER_PRIMARY_SOURCE_REVIEW.md new file mode 100644 index 0000000..4e1f170 --- /dev/null +++ b/docs/dev/INSTALLER_PRIMARY_SOURCE_REVIEW.md @@ -0,0 +1,227 @@ +# Rieke OS installer source review + +The later [Electron production specification](../design/electron-production-spec.md) +records the selected architecture. The Sparkle recommendation below was the +earlier alternative; the packaging, signing and service-lifetime constraints +remain relevant. + +Reviewed 2026-09-29. Scope: Apple Silicon macOS, a local Python/Flask service, +React assets, private MySQL, and releases on GitHub. This is planning evidence; +no installer or signed update was built in this review. + +## Recommended architecture + +Use one immutable, Developer-ID-signed and notarized `Rieke OS.app`. A small +native AppKit launcher owns the app lifetime, starts the bundled Python services, +opens the local UI, and drains those services before quitting. Bundle the +prebuilt frontend, portable Python with installed packages/parser/utilities, and +the already-relocated MySQL dependency closure. Keep projects, SQL data, +configuration, logs, update caches and receipts outside the app bundle. + +Use Sparkle as the **only desktop update authority**, replacing complete signed +app bundles. Adapt Release / Publish to display its state and open its controls. +Do not let the existing Python manager concurrently stage/activate desktop +code. Keep that manager only for explicitly separate source installations if +they remain supported. + +This supersedes the current custom source-activation design for desktop builds; +it is a proposed change in update architecture, not functionality already shipped. + +This recommendation follows Apple's sealed-bundle rules and Sparkle's existing +signed bundle-update machinery, rather than proving our bespoke source manager +into a new macOS installer/updater. The repository's existing project locks, +database-generation gates and staging tests remain useful specifications; they +are not automatically preserved by adopting Sparkle. + +## Source facts and implications + +### Signing and notarization + +**Fact:** Apple requires Developer ID signatures, hardened runtime and secure +timestamps for notarization, with valid signatures on distributed executables. +Its notary service supplies a ticket that can be stapled to the distributed +software. Current submission uses `notarytool`, not the retired `altool` +workflow. [Apple notarization requirements](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution). + +**Fact:** Modern bundle signatures seal essentially all content. Apple says to +treat signed bundles as read-only, sign nested code before the enclosing bundle, +and put scripts/resources and executable code in appropriate locations. +Absolute links to libraries outside the bundle can fail Gatekeeper. +[Apple TN2206](https://developer.apple.com/library/archive/technotes/tn2206/_index.html). + +**Implication:** First-launch `pip` installation, Python bytecode written inside +the bundle, frontend builds, conda prefix rewriting, ad-hoc re-signing and +receipts inside `Contents` are incompatible with the intended sealed product. +Finish code transformations in CI, then sign. Route bytecode/cache writes outside +the bundle or disable bytecode writes. Never use a local ad-hoc signature as the +distribution identity. Entitlements must be proven by the packaged imports and +subprocesses; avoid broad exceptions by default. + +**Repository gap:** The custom source archive extractor rejects symlinks and +limits archives to 512 MiB compressed / 2 GiB extracted. It cannot be reused +unchanged for framework-containing `.app` bundles. Sparkle explicitly requires +packaging to preserve symlinks and executable permissions. +[Sparkle bundle integration](https://sparkle-project.org/documentation/). + +### Relocation and downloaded-app behavior + +**Fact:** App Translocation runs a downloaded app at a randomized path. Apple +does not document all trigger conditions and provides no supported detection +or way to recover the original path. Resources outside the bundle, found by +walking from its path, can break. Apple recommends making the app work while +translocated. [Apple DTS App Translocation Notes](https://developer.apple.com/forums/thread/724969). + +**Implication:** Resolve packaged resources from the actual bundle, never the +shell's working directory or a build-time checkout. Test launch after browser +download, from Downloads, after moving the app, and with spaces/non-ASCII paths. +A supported install flow should put the app in a writable permanent location; +do not rely on deleting quarantine attributes or reconstructing original paths. + +### Python packaging choices + +**Fact:** `python-build-standalone` publishes portable distributions, including +`aarch64-apple-darwin`, with `install_only` archives for running Python. Its +current release home is Astral's GitHub repository. [Project running guide](https://gregoryszorc.com/docs/python-build-standalone/main/running.html). + +**Fact:** Build-time absolute paths remain in configuration such as sysconfig +data/Makefiles; uv fixes these for its installed distributions. Portability of +the interpreter does not promise portability of packages installed beside it. +[Project behavior quirks](https://github.com/astral-sh/python-build-standalone/blob/main/docs/quirks.rst). + +**Fact:** Python's ordinary virtual environments are not considered movable or +copyable; script shebangs contain absolute interpreter paths. +[Python venv documentation](https://docs.python.org/3/library/venv.html). + +**Inference:** First choice is a pinned standalone interpreter with packages +installed at build time into a controlled private layout and launched by its +explicit bundled executable. Build a wheel for the pinned parser rather than +ship an editable install. Precompile its C/C++ utilities. Verify NumPy, SciPy, +HDF5/h5py and every native extension against the supported macOS baseline and +architecture. This remains a proof obligation, not a claim that copying today's +`.venv` will work. + +**Alternative fact:** PyInstaller collects Python dependencies and supports +macOS signing identity and entitlement configuration. Binary-path rewriting +invalidates signatures, so binaries must be re-signed afterward. Its `onefile` +mode extracts a payload to a temporary directory and uses launcher/child +processes. [PyInstaller feature notes](https://pyinstaller.org/en/stable/feature-notes.html). + +**Inference:** PyInstaller `onedir` workers inside the native app are a viable +fallback if the standalone layout proves costly. It still needs explicit +collection of dynamic parser imports, data files and native utilities. Avoid +`onefile` for long-lived detached project workers whose files must survive the +bootstrap process. Neither approach automatically bundles MySQL or supplies +app lifecycle/update coordination. + +### MySQL relocation before signing + +**Fact:** Oracle's macOS installer installs under `/usr/local`, offers launchd +support and does not permit changing the installation location. +[MySQL macOS package documentation](https://dev.mysql.com/doc/refman/8.4/en/macos-installation-pkg.html). + +**Fact:** MySQL supports explicit `--basedir`/`--datadir` for manual data-directory +initialization. [MySQL initialization documentation](https://dev.mysql.com/doc/refman/8.4/en/data-directory-initialization.html). + +**Repository evidence:** `python/workspace_mysql_runtime.py` currently links +conda packages at the destination prefix, changes Mach-O bytes and restores +ad-hoc signatures. This is useful for source installs but cannot run inside a +sealed desktop bundle. + +**Inference/proof obligation:** Prepare MySQL, `mysql`, `mysqldump`, plugins, +OpenSSL and the complete dynamic-library closure in CI. Inspect dependencies +and use supported relative Mach-O load paths. Verify strings/config files that +encode the conda prefix and paths to plugin/share resources. Only then apply +Developer ID signatures to final bytes. Run server/client/dump after moving the +finished app to different users and paths; a successful `--version` probe alone +does not prove TLS, authentication plugins, import or backup. Keep each project's +datadir, sockets, error logs and credentials outside the app. Do not install +Oracle's system daemon as the app-private runtime strategy. + +### Sparkle automatic update behavior + +**Fact:** Sparkle checks are opt-in by default and normally show a permission +request on second launch. Set `SUEnableAutomaticChecks=YES` in `Info.plist` to +enable checks without that request. Set `SUAutomaticallyUpdate=YES` to enable +automatic download/install; its default is `NO`. Scheduled checks default to +one day with a minimum one-hour interval. A downloaded update may prompt after +the impatient interval (default one week), or need authorization. +[Sparkle customization](https://sparkle-project.org/documentation/customization/). + +**Fact:** `willInstallUpdateOnQuit` is called when an automatic update is ready +for silent installation on quit. Returning `YES` takes control and stalls future +update cycles; its handler can install/relaunch without UI. In either case +Sparkle still attempts installation when the app terminates. +[Sparkle updater delegate](https://sparkle-project.org/documentation/api-reference/Protocols/SPUUpdaterDelegate.html). + +**Fact:** A custom `SPUUserDriver` must present UI; it cannot simply suppress all +UI. Silent behavior comes from automatic-update configuration. Package updates +always require authorization, and app updates may require it on managed Macs or +for standard users in `/Applications`. +[Sparkle custom UI contract](https://sparkle-project.org/documentation/custom-user-interfaces/). + +**Inference:** Prefer a user-owned installation such as `~/Applications` when +unprompted subsequent updates are a requirement. A standard DMG drag/install or +small installer still involves normal OS/download gestures; do not advertise a +literally single click or bypass macOS first-open prompts. Bridge update state +to the existing badge; retain a proper UI for manual actions and authorization. +Test the impatient/critical-update paths before claiming no unsolicited update +dialogs. Install on orderly app quit so the next ordinary launch uses the new +version; do not update beneath active workers. + +**Fact:** Sparkle supports signed update archives and an appcast, uses an +embedded EdDSA public key, and supports multiple archive formats including DMG +and ZIP. [Sparkle setup and publication guide](https://sparkle-project.org/documentation/). + +**Inference:** Publish complete notarized app archives as GitHub Release assets +and a stable appcast URL containing their exact URLs/signatures. Code signing, +notarization and Sparkle's EdDSA signing are separate trust tasks. A Git push +does not itself publish a valid update. Remove the desktop RSA-manager channel +as an activation authority rather than maintain two independent trust/update +pipelines for the same application. + +### Process and service ownership + +**Fact:** Python recommends fully qualified executable paths for subprocess +reliability. `start_new_session`/`process_group` manage POSIX sessions/groups; +they do not define application-level lifetime or request drainage. +[Python subprocess documentation](https://docs.python.org/3/library/subprocess.html). + +**Fact:** Flask says not to use its development server in production. +[Flask server guidance](https://flask.palletsprojects.com/en/stable/server/). + +**Inference:** Use a bundled production WSGI server on loopback, disable reload +mode, establish readiness before opening the browser, handle duplicate launches +and occupied ports, and let AppKit remain alive while any project service is +active. Closing a browser tab must not be treated as shutdown acknowledgement. +Stop accepting new work, preserve drafts, drain workers and shut down owned +MySQL servers before the app terminates. If shutdown cannot complete safely, +cancel termination and defer installation. + +## Bespoke manager fallback + +Retaining the existing manager is feasible only with additional work: give it +its own bundled bootstrap interpreter that remains available independently of +the active version; stage prebuilt artifacts without `setup` compilation; +handle final signing/notarization, launcher replacement, manager/key upgrades, +failure recovery and macOS authorization. The existing `sys.executable` and +`#!/usr/bin/env python3` entry points do not establish that stable offline +bootstrap contract. This route must also preserve bundle sealing by replacing +complete signed payloads rather than modifying their code. It has more +unimplemented desktop-specific responsibilities than the proposed Sparkle +route. This comparison is engineering judgment based on the source contracts, +not a completed packaging experiment. + +## Evidence required before release + +1. A moved, sealed app runs offline on a clean supported Apple Silicon Mac with + no Python, uv, Git, Node, Homebrew, compiler, Docker or MATLAB dependency. +2. All compiled imports, parser utilities and real MySQL import/edit/export, + restart and dump/restore work from the packaged layout. +3. Gatekeeper/notarization verification succeeds after a genuine browser + download; startup leaves bundle signatures valid. +4. A real published old-to-new Sparkle update downloads quietly, waits for all + workers, installs on quit and preserves project data/preferences. +5. Offline checks, corrupt signatures, interrupted download, disk-full, busy + workers, permission failure and incompatible database versions defer safely. +6. Recovery and schema compatibility are tested explicitly; replacing an app + binary is not permission to migrate or downgrade project databases. diff --git a/docs/dev/NATIVE_E2E_VALIDATION.md b/docs/dev/NATIVE_E2E_VALIDATION.md index 9d9a8a6..2bafe9a 100644 --- a/docs/dev/NATIVE_E2E_VALIDATION.md +++ b/docs/dev/NATIVE_E2E_VALIDATION.md @@ -116,8 +116,36 @@ pauses expiry. Clicking View details opens the import workbench. Existing histor is not replayed as new notifications after reload. Completion no longer opens a modal automatically; the review dialog is available explicitly from Review import. The browser verified a real duplicate import notification and automatic expiry, -with no persistent header bar or automatic review dialog. App update notices also -expire; their availability indicator remains in Release / Publish. +with no persistent header bar or automatic review dialog. App updates now appear +quietly as a persistent Update badge in Release / Publish, without a toast. + +## Quiet updates and publication audit — 2026-09-29 + +- Checked both live GitHub repositories. The development checkout's updater + pointed at epicTreeGUI, whose release channel is empty. Rieke-OS is the actual + public distribution, with stable source releases through v0.1.2 and one source + installation verification workflow. Corrected discovery and release URLs to + Rieke-OS; a fresh backend check returns `update_available`, available `0.1.2`, + and `can_stage: false` for this development checkout. +- Browser preview with simulated update responses verified the persistent + Update/Ready row, no update toast or automatic dialog, opening/closing the + panel without dismissing availability, retaining the known update after a + failed refresh, and clearing it after a successful up-to-date response. + [Simulated Ready preview](quiet-update-ready-preview.jpg). +- 50 relevant updater, route, workspace installation and bootstrap tests pass; + frontend logic tests and production build pass. The manager subprocess test + uses minimal fixture applications to exercise real interprocess locks and + next-launch selection. It verifies deferral while another holder is open, + activation after closure, retention of the previous release, and preservation + of preferences. It is not a real old-to-new production application upgrade. +- Prepared a tag-triggered signed build and protected publication job; its + publication condition allows only Rieke-OS. No workflow was dispatched and no + release was published. The updater and workflow still need to be carried into + the public distribution, with signing configured and real upgrade validation. +- The one-click desktop installer remains unfinished. Existing source releases + bootstrap development tools and dependencies; they are not offline prebuilt + applications. MATLAB is required only for the optional EpicTreeGUI workflow, + not core app launch, import, or updating. ## Pinned query approval demonstration @@ -158,3 +186,267 @@ Successful import completion now opens the global Review imported data dialog fr Removed the duplicate Import progress toolbar button. Import H5s now changes to Importing H5s while work is active and opens the same import/history page. File selection and drop accept multiple H5s, queued at app scope, with only one submitted import at a time. Upload uncertainty or failed imports stop the queue; no automatic POST retries occur. Keep the tab open for browser-held pending files. Browser file chooser confirmed multiple selection. Submitted a new synthetic H5 followed by an existing H5: first completed at 18:51:28 UTC, second started at 18:51:28.919 UTC and was skipped as duplicate. Review appeared after the queue drained, preserving the successful import review despite the last file being a duplicate. Frontend 211 tests and production build passed. + +## Project portability audit (2026-09-29) + +- Added explicit **Add new project** and **Start a brand new project** actions in + the left sidebar. The first recognizes an ordinary project or a received + transfer, and automatically shows the verified-copy restore form. The second + creates the selected exact project folder and its managed storage/database. +- The browser created a disposable native project, imported a read-only real + Symphony recording (5 cells, 690 epochs), closed it, prepared a checked copy, + added that received copy through the ordinary project action, restored it into + a fresh folder and opened its overview and protocols. Both sidebar actions and + the verified restore confirmation were visually checked. + [Recipient restore](portable-project-restore-e2e.png) and + [recipient sidebar](portable-project-sidebar-e2e.png). +- A production API integration test saved two named predicate versions, a query + run, an explorer baseline, authored tags, review/inclusion decisions, a tree + layout, recent-search shortcuts, protocol pins and a failed-job record. It + prepared a transfer, removed the entire disposable donor, restored to a fresh + runtime, then compared the actual recipient API responses and 16 waveform + samples. The recipient overview also opened successfully. +- Packages now preserve durable import/app-job/error/storage history, portable + search/navigation preferences and every SQL table. Each new package records + table columns, row counts and content checksums; restore compares these before + updating current file locators. H5 files with external dependencies and damaged + preferences are rejected before a recipient database is started. +- Native tests also exercise both never-opened and opened/closed empty projects, + independently restored copies, donor recording removal, safe rejection of + missing identity in populated projects and failed restore cleanup. +- Browser pinning and running a History noise search wrote both choices into + `protocols/ui-state/project-preferences.json` (72 epochs, 2 cells). Failed old + browser-preference migration preserves its cache across refresh until a save + succeeds; stale incoming/browser values and concurrent changes have coverage. +- Final backend workspace suite: **705 tests passed**, with native MySQL, + native transfer and production API portability gates enabled; no skips. + Frontend: **251 tests passed** and production build passed. Whitespace checks + passed. Original recordings and research projects were not modified. + +Reproduce the full backend checks with a suitable real Symphony fixture: + +```sh +RIEKE_TEST_NATIVE_MYSQL=1 RIEKE_TEST_NATIVE_TRANSFER=1 \ +RIEKE_TEST_PORTABLE_APP=1 RIEKE_PORTABILITY_H5=/absolute/path/to/recording.h5 \ +PYTHONPATH=python .rieke-runtime/venv/bin/python -m unittest discover \ + -s python/tests -p 'test_*workspace*.py' +``` + +These checks use fresh folders, credentials and native runtimes on one Apple +Silicon Mac. A physical second-computer or other-platform transfer remains +unverified. Restart existing app services to load the new backend before using +the rebuilt interface. + +### Project UI design follow-up + +The chooser now uses two icon-led action cards, a six-icon project contents +graphic, compact folder names and a collapsed preferred-location control. +The closed-project notice is a compact status row. The project dialog uses +**Open / Share / Receive** tabs and shows one task at a time, including concise +file verification and restore results. Native sharing shows the close action +before destination fields. Keyboard tab navigation and accessible control names +are preserved. + +The real received-copy flow was exercised again through the redesigned dialog. +Frontend: 251 tests passed and production build passed. Narrow layouts were +visually checked; the closed-notice dismiss/copy controls stay on the same row. + +Final browser checks also covered invalid-folder rejection and refusal to +restore into an existing destination. SHA-256 comparisons confirmed that the +existing project's manifest, catalog, database credentials and guard file were +unchanged. The new-project form created all managed folders, opened the empty +production overview, and closed cleanly. Design screenshots are saved as +`portable-project-chooser-design.png`, `portable-project-share-design.png` and +`portable-project-restore-e2e.png` alongside this report. + +### Project roots anywhere and nearby-folder suggestions + +Project creation, open, verified restore and relocation now remember exact +project roots in a local user-profile index. Inventories retain roots outside +the preferred location across closing and launcher restart, preserve independent +native copies by path, and show unavailable external drives. Exact creation and +opening do not write app registry or lock files into the project's parent. +Prepared transfer folders are excluded from live-project discovery. + +Folder inspection proposes the nearest fully validated containing root for +a nested selection, or valid immediate children for a parent selection. Searches +are bounded to eight ancestors and 128 immediate entries; no recursive drive +scan, runtime start or automatic candidate selection occurs. The UI lists each +candidate with **Use this folder**, followed by an explicit Open or Check action. + +The production service flow opened an external project after detecting its root +from `imports/`, closed its database cleanly and retained that exact root in the +launcher inventory. Receipt: `project-root-location-verification.json`. +Final full native backend suite: **803 tests passed**; frontend: **266 tests +passed** and production build passed. Live browser automation was unavailable +for a visual recheck of the new suggestion cards; API and frontend logic checks +passed. Refresh the preview after restarting its service to load the changes. + +### Final review before push + +The browser connection recovered for the final UI review. Naming guidance and +the matching name/folder preview, Back and Escape, parent and nested folder +suggestions, explicit candidate selection and prepared-copy detection all passed. +Editing a received path clears its earlier verification. Current screenshots: +`portable-project-naming-design.jpg`, `portable-project-root-suggestions.jpg` +and `portable-project-receive-verified.jpg`. + +Review fixes reject missing package metadata even when a checksum is null, +serialize managed and exact creation of the same folder, reapply sidebar move +intent after a preference conflict, preserve completed operations when saving +the local project index fails, and keep malformed old browser shortcuts from +crashing the search screen. The original browser cache is retained until a +successful save. Regression tests cover each failure. + +The push is prepared from a separate snapshot based on the current committed +code plus only the project portability changes and required dependencies. +Unrelated desktop, update, source-identity and performance edits are excluded. +The initial snapshot passed 693 backend tests with all native portability gates +enabled, 244 frontend tests and the production build. The final safeguards were +then incorporated and checked again before commit. + +Final feature-only snapshot: **697 backend tests passed**, all native gates +enabled with no skips; **245 frontend tests passed** and production build passed. +Whitespace checks passed. The additional tests in the larger shared working +tree belong to other ongoing changes and are not part of this push. + +### Project popup follow-up + +The project rail **+** now opens a native modal chooser above the existing app. +Creation stays within that popup; the welcome screen also opens creation in a +modal. A live disposable workspace verified that its overview URL and contents +remain in place, **×** and **Escape** return focus to **+**, and forward/reverse +Tab stay inside the popup. No project files were created by this UI check. +Screenshots: `project-popup-over-workspace.jpg` and +`project-create-popup-over-workspace.jpg`. The feature-only frontend suite and +production build were checked again for this UI correction. + +## Project folder browser and creation actions — 2026-09-29 + +Every editable project location now has Browse: creation, preferred location, +opening, moving, sharing and receiving. The browser fallback navigates immediate +folders with location shortcuts, parent navigation and explicit new-folder names. +It reads folder metadata only and never creates files. The optional desktop +chooser contract is covered by adapter tests; a native OS dialog was not exercised +in this browser validation. + +A scoped checkout passed 253 frontend tests, the production build, 11 new folder +API tests and 10 existing open-folder tests. Folder tests include pagination, +permission errors, same-origin local access, missing destinations and occupied +folders containing only hidden entries or files. + +Live browser validation confirmed the new-project popup has Cancel and Create & +open above the existing workspace. Escape from the nested folder browser preserved +the project name and folder value, kept setup open and returned focus to Browse. +[Creation popup](project-create-browse-cancel.jpg) and +[Folder navigator](project-browse-picker.jpg). + +Main Cancel closed setup and restored focus to its sidebar opener at the same +overview URL. Tab/Shift+Tab remained in the nested picker. Choosing a proposed +new folder filled the form without creating that folder on disk. + +Final audit regression: a missing proposed child inside an empty parent now stays +a new-folder proposal rather than selecting its parent. The API reports whether +the requested directory exists; the picker preserves the entered child name. A +live check returned the exact proposed child path, while its parent stayed empty +and the child was not created. Unfinished typed paths can still open Browse. +10 focused folder-client tests, 12 folder API tests and the scoped production +build pass. [Empty-parent check](project-browse-empty-parent-regression.jpg). + +## Whole UI file and folder audit — 2026-09-29 + +Reviewed the entire component directory and App import/export pages, searching all +inputs, file-picker triggers, editable paths and copy-path actions. + +| Flow | File or folder action | +| --- | --- | +| New project / preferred projects location | Browse folders | +| Open / move / share / receive project | Browse sources and destination folders | +| Recording import | Browse H5 files; multiple selection and drag/drop | +| Tag and saved-query import | Native JSON file picker buttons | +| Selection masks | Native UGM and JSON file picker buttons | +| Exports | Download buttons; Open exports folder for local handoff | +| Project files | In-app categories, folders and breadcrumbs | +| Tag author profile | Author list and name; preferences saved automatically | + +The H5 chooser was a styled label around a hidden input, leaving it outside +keyboard navigation. It now uses a real Browse button with the same file filters, +multiple-file selection, queue behavior and disabled state. Cancel enqueues +nothing; resetting the input allows choosing the same recording again. + +The local exports card previously offered only Copy folder path. Open exports +folder now opens this project's existing exports folder in the system file +manager. Its endpoint accepts an empty body only, verifies a local app request, +and rejects missing folders and symlinks. It cannot choose an arbitrary location. +Copies, exports and original recordings keep their current storage layout. + +A scoped checkout passed 255 frontend tests, 18 folder API tests, 10 existing +open-folder tests and the production build. File-picker controls for tags, queries +and masks already existed. Filename/path search filters and readonly diagnostic +paths do not prompt for a filesystem selection. + +Live browser checks: Tab focused the H5 Browse button and Enter emitted a +multiple-file chooser event. No files were selected and import history remained +empty. Clicking Open exports folder completed without a visible error and +re-enabled the button; success requires the OS opener to exit successfully for +the fixed fixture exports path. The native computer-use service was unavailable +for Finder, so the Finder window itself was not visually inspected. +[H5 Browse](ui-browse-h5-audit.jpg) and +[Open exports folder](ui-open-exports-audit.jpg). + + +## Final unsigned Electron artifact validation — 2026-09-30 UTC + +The final local DMG and ZIP passed the complete packaged checks. See +[the consolidated receipt](desktop-final-e2e-receipt.json) for exact artifact +hashes, the runtime manifest and per-suite evidence. The app contains 40,172 +runtime resources and 798 native binaries. + +- 955 Python tests passed; 15 optional tests skipped. +- 291 frontend and 27 desktop unit tests passed. +- 21 real packaged UI/lifecycle checks and a separate broken-backend startup + case passed, including actual H5 import, bridge/native close deferral, draft + recovery, rapid project handoff, cold restart and renderer crash recovery. +- 15 real scientific cases passed, including reference/SQLite/MAT numeric + fidelity, native portability, a separate legacy copy and monitor crash with + the importer retaining its project lease. +- Extracted DMG/ZIP resource and native audits, 23 rejection faults, isolated + native restart/backup/restore and DMG-extracted recording workflow passed. +- 10 pinned updater transport scenarios passed with zero unhandled rejections + and zero native installs, including a fresh-client retry after interruption. + +All scientific test services exited cleanly. Original H5 and packaged resource +checksums stayed unchanged. Normal desktop operation requires no Docker. The +legacy-copy fixture used a test Unix inspection transport with real native SQL, +scientific data and history. No user source database or project was migrated. +Frozen historical exports retain their original pointers; a new migrated export +was separately verified against the copy’s H5 data. + +The user’s older installed app was left running and was not replaced. The +reference bundle for the artifact audit was the built candidate; extracted DMG +and ZIP copies were tested at isolated paths. This is an unsigned dirty-source +local candidate. Signing/notarization, real signed old-to-new installation and +recovery, a second clean machine/different user and macOS 14.0 remain release +gates. No MATLAB engine was used; MAT structure and lazy numeric pointers were +checked with bundled SciPy and H5. Native chooser results were stubbed at the OS +dialog boundary. The receipts do not claim universal OS shutdown or power-loss +qualification. + +The upper-right app icon update was rebuilt and rerun through the same packaged +UI, startup-failure, scientific and DMG/ZIP audits. The actual bundled purple R +loads at 48 px in the launcher and 32 px in the workspace. Native 1440 px and +960 px window checks confirm that the icon remains visible without overlapping +the toolbar. See the [workspace preview](desktop-ui-e2e/workspace-icon-1440.png) +and [narrow preview](desktop-ui-e2e/workspace-icon-960.png). The final consolidated +receipt records the refreshed artifact hashes; all five published files remained +unchanged during verification. + +An additional [no-Docker recording workflow](desktop-no-docker-e2e.json) passed +against the same final packaged runtime. Separate negative controls rejected +three container command executions and two Docker socket connections before +host access. With a fresh HOME and restricted PATH, project creation, real H5 +import, tags, query, reference export, reopen and orderly shutdown passed with +zero container command or non-MySQL Unix socket attempts. Packaged resources +remained unchanged; the user's Docker daemon and installed app were untouched. +This uses Python process/socket instrumentation and the exact bundled native +MySQL executable, rather than a kernel sandbox or clean-machine qualification. diff --git a/docs/dev/TAG_SCOPE_AND_PROFILE_AUDIT.md b/docs/dev/TAG_SCOPE_AND_PROFILE_AUDIT.md new file mode 100644 index 0000000..287a71c --- /dev/null +++ b/docs/dev/TAG_SCOPE_AND_PROFILE_AUDIT.md @@ -0,0 +1,62 @@ +# Tag scope and user attribution + +Reviewed 2026-09-28. This records the integration contract, not an implemented migration. + +## Reference behavior + +Upstream: https://github.com/SamarjitK/datajoint +Local fork: /Users/maxwellsdm/Documents/GitHub/datajoint (origin maxwellsdm1867, upstream SamarjitK). + +- next-app/api/schema.py:255: Tags attaches tag text and user to a table/object identity and its H5 UUID. +- next-app/api/helpers/query.py:106–147: tag predicates restrict the selected hierarchy level; joins carry matching cells down to their epochs. +- query.py:357–375: tagging selected cells writes cell records, not duplicated epoch records. Current deletion lacks a user restriction; do not copy that ownership behavior. +- query.py:380–470: hierarchical JSON keyed by H5 UUID retains user/tag pairs. Push exports the current user's tags, pull imports other users, reset reloads all. +- src/app/components/results/CustomTreeItem.js:65: compound chips show tag plus author. +- src/app/components/setup/SetUser.js and api/app.py:189: selectable username; this is attribution, not authenticated identity. +- Local fork query.py:473 and ResultsViewer.js:145: .ugm import translates deselection into the current user's excluded tag. This local extension is not asserted to exist upstream. + +## Current Rieke OS gaps + +workspace_curation.py stores tags at project + protocol + epoch scope. Bulk selection applies that scope to explicit epoch UUIDs. It is not a durable cell tag. Events record an actor, but current routes use the operating-system USER. The tag list does not retain per-tag authorship. Predicates expose explicitly named protocol tag fields in workspace_tag_predicates.py. No selectable profile or shared cell/epoch annotation layer exists yet. + +workspace_matlab_routes.py already validates .ugm against an exact completed export, source metadata, query and curation revisions. Inclusion updates are transactional, preserve tags and non-exported epochs, and log input hashes. Preserve these checks. + +## Target semantics + +| Entry | Stored target | Effective scope | +|---|---|---| +| Tag cell | project UUID + cell UUID | All epochs linked to that cell, across protocol datasets | +| Tag epoch | project UUID + epoch UUID | That epoch only | +| Tag selected epochs | explicit epoch UUID set | Only those selected epochs | +| Protocol curation | existing protocol + epoch IDs | Existing dataset-specific decisions remain separate | + +Cell tags inherit through identity joins, not copied rows. Newly registered epochs linked to the same cell inherit automatically. A future epoch that belongs to a different cell named Cell1 must not inherit. Filtering a view must not silently narrow a cell-level tag to only its visible epochs. + +Deleting a cell tag removes its inherited appearance; an independently authored epoch tag of the same text remains. Cell and epoch tags authored by different users remain distinguishable. Tags are annotations, not implicit include/exclude commands. + +## Persistence and UI + +Add explicit Profile and Annotation bookkeeping tables. Profile: UUID, display name, created/updated timestamps. Annotation: project, target kind, target UUID, author UUID, exact tag text, revision, created/updated timestamps, retired state. Use a unique target/author/tag constraint and append-only change events. Resolve active profiles per client session/request, not a single server-global username. Historical event names must remain interpretable if a profile is renamed. + +Keep existing protocol tags in place with their original scope. Do not invent authors for historical tags or automatically promote them to cell annotations. Any explicit migration should preserve original event provenance and mark unknown authorship. + +Use the far-left profile control to select/create a local profile. In cell details, show Cell tags and their affected epoch count; in epoch details, show Direct epoch tags and Inherited from cell. Chips show tag, scope and author without repeating long UUIDs. Inherited chips link to the parent cell editor. Suggestions come from persisted project tags; show existing authorship rather than duplicate chips silently. + +Search predicate fields must distinguish Cell keywords, Epoch keywords, Effective tags, Author, and existing Protocol tags. Imported acquisition keywords remain identifiable as source metadata. Exact tag matching and text searching are different operators. + +Export the annotation snapshot with target IDs, authors, scope, and revisions. Wheeler SQLite and MATLAB handoffs must distinguish inherited cell tags from direct epoch tags and from selection masks. Frozen exports do not change when later annotations change. + +Mask imports should offer a preview of included/excluded counts, matched export and affected epochs. Apply only inclusion decisions to the intended protocol/export scope. Do not implement masks by deleting or overwriting user tags. + +## Required validation before shipping + +- Same Cell1 label on different dates never cross-tags. +- Cell tags appear on all linked epochs across protocol and predicate views, including later-added epochs. +- Direct epoch tags remain on only the intended epoch. +- Removing inherited tags preserves independent tags with identical text. +- Two users' same-text tags remain independently attributable. +- Concurrent edits reject stale revisions and log committed changes once. +- Cell/epoch/effective-tag and author predicates give exact UUID memberships. +- Both exports retain attribution and inheritance while old export snapshots stay unchanged. +- .ugm import preserves all tags, rejects unknown/mismatched/stale IDs and remains idempotent. +- Paged epoch views retrieve inherited annotations in batches; no per-epoch SQL round trips or waveform loads. diff --git a/docs/dev/portable-project-chooser-design.png b/docs/dev/portable-project-chooser-design.png new file mode 100644 index 0000000..7d28d1f Binary files /dev/null and b/docs/dev/portable-project-chooser-design.png differ diff --git a/docs/dev/portable-project-naming-design.jpg b/docs/dev/portable-project-naming-design.jpg new file mode 100644 index 0000000..2facd6e Binary files /dev/null and b/docs/dev/portable-project-naming-design.jpg differ diff --git a/docs/dev/portable-project-receive-verified.jpg b/docs/dev/portable-project-receive-verified.jpg new file mode 100644 index 0000000..da073b5 Binary files /dev/null and b/docs/dev/portable-project-receive-verified.jpg differ diff --git a/docs/dev/portable-project-restore-e2e.png b/docs/dev/portable-project-restore-e2e.png new file mode 100644 index 0000000..c28c533 Binary files /dev/null and b/docs/dev/portable-project-restore-e2e.png differ diff --git a/docs/dev/portable-project-root-suggestions.jpg b/docs/dev/portable-project-root-suggestions.jpg new file mode 100644 index 0000000..f00abf3 Binary files /dev/null and b/docs/dev/portable-project-root-suggestions.jpg differ diff --git a/docs/dev/portable-project-share-design.png b/docs/dev/portable-project-share-design.png new file mode 100644 index 0000000..327ae18 Binary files /dev/null and b/docs/dev/portable-project-share-design.png differ diff --git a/docs/dev/portable-project-sidebar-e2e.png b/docs/dev/portable-project-sidebar-e2e.png new file mode 100644 index 0000000..45670a9 Binary files /dev/null and b/docs/dev/portable-project-sidebar-e2e.png differ diff --git a/docs/dev/project-browse-empty-parent-regression.jpg b/docs/dev/project-browse-empty-parent-regression.jpg new file mode 100644 index 0000000..c6ce33e Binary files /dev/null and b/docs/dev/project-browse-empty-parent-regression.jpg differ diff --git a/docs/dev/project-browse-picker.jpg b/docs/dev/project-browse-picker.jpg new file mode 100644 index 0000000..bf6fa8a Binary files /dev/null and b/docs/dev/project-browse-picker.jpg differ diff --git a/docs/dev/project-create-browse-cancel.jpg b/docs/dev/project-create-browse-cancel.jpg new file mode 100644 index 0000000..a5c7373 Binary files /dev/null and b/docs/dev/project-create-browse-cancel.jpg differ diff --git a/docs/dev/project-create-popup-over-workspace.jpg b/docs/dev/project-create-popup-over-workspace.jpg new file mode 100644 index 0000000..eaaa02d Binary files /dev/null and b/docs/dev/project-create-popup-over-workspace.jpg differ diff --git a/docs/dev/project-popup-over-workspace.jpg b/docs/dev/project-popup-over-workspace.jpg new file mode 100644 index 0000000..d88c310 Binary files /dev/null and b/docs/dev/project-popup-over-workspace.jpg differ diff --git a/docs/dev/project-root-location-verification.json b/docs/dev/project-root-location-verification.json new file mode 100644 index 0000000..da5b02c --- /dev/null +++ b/docs/dev/project-root-location-verification.json @@ -0,0 +1,9 @@ +{ + "nested_folder_suggested_exact_root": true, + "external_root_opened": true, + "project_uuid": "96e2ddc1-f9ed-471b-86ce-6fa1f7751d51", + "database_closed_cleanly": true, + "external_root_remains_in_chooser": true, + "preferred_root": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-portability-ui-s1wdbe4f/projects", + "selected_root": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-portability-ui-s1wdbe4f/New design project" +} diff --git a/docs/dev/releases/0.1.3-source-validation.json b/docs/dev/releases/0.1.3-source-validation.json new file mode 100644 index 0000000..df13b82 --- /dev/null +++ b/docs/dev/releases/0.1.3-source-validation.json @@ -0,0 +1,39 @@ +{ + "format": "rieke-source-release-validation", + "version": 1, + "application_version": "0.1.3", + "channel": "unsigned-testing", + "checked_at": "2026-09-30T16:04:32.127523+00:00", + "source_files": 554, + "source_sha256": "80a5a14af9c4f0ce8205ef818cd37a33c46d9e2218d0460dcc180cfa8861bc8d", + "source_unchanged_during_validation": true, + "checks": { + "python_native_enabled": { + "passed": 1115, + "skipped": 1, + "subtests": 2792 + }, + "previously_skipped_real_recording_portability": { + "passed": 1, + "source_recording_read_only": true, + "disposable_projects": true + }, + "frontend": { + "passed": 322 + }, + "frontend_production_build": { + "passed": true + }, + "desktop": { + "passed": 61, + "source_unchanged_during_run": true + }, + "coordinated_versions": { + "passed": true + }, + "diff_whitespace": { + "passed": true + } + }, + "artifact_qualification": "Performed separately against the rebuilt package from the canonical source commit. This source receipt does not certify installer bytes, Developer ID signing, or notarization." +} diff --git a/docs/dev/releasing-rieke-os.md b/docs/dev/releasing-rieke-os.md index 9e5205d..96e11ad 100644 --- a/docs/dev/releasing-rieke-os.md +++ b/docs/dev/releasing-rieke-os.md @@ -4,6 +4,78 @@ The updater is a foundation for signed application releases, not `git pull`. Development checkouts can check the official GitHub release channel but cannot install into themselves. A missing GitHub release is reported as unavailable. +## Publication to update discovery + +The application checks `https://api.github.com/repos/maxwellsdm1867/Rieke-OS/releases/latest`. +PyPI and TestPyPI are not update sources. A Git push, version tag, or Actions +candidate artifact alone does not make an update visible to users. The candidate +must be promoted to a published stable GitHub Release with its signed manifest +and matching platform bundle attached. Publish it as the latest release only +after the validation gates below pass; drafts and prereleases are excluded. + +The app checks on startup, every 15 minutes while visible, and on return after +that interval. A newer stable version highlights Release / Publish with an Update +badge, without a toast or automatically opened dialog. Clicking it shows release +notes and download progress. Trusted managed installations automatically download +and verify the update. Transient check +failures retain an already discovered update and explain the failure inside the +panel. After the chooser and all project services have closed, the next launch +through the stable manager activates the prepared release. A busy installation +continues using its current version; updates never force-close another service. + +There are two distinct repositories, as checked on 2026-09-29: + +| Repository | Current publication state | +| --- | --- | +| `maxwellsdm1867/epicTreeGUI` (this development checkout) | Regression and signed-candidate workflows; no tags or releases, no configured environments or repository Actions secrets visible to this account. The previous updater incorrectly checked this empty release channel. | +| `maxwellsdm1867/Rieke-OS` (public app distribution) | Stable versions through `v0.1.2`, with a source ZIP and SHA256SUMS. Its sole workflow verifies source installation. It has no updater module, signed update manifest, or prebuilt desktop installer. | + +This change points discovery, release links and future signed artifact URLs at +Rieke-OS. The updater, metadata, UI and release workflow must be carried into that +distribution before its users receive them. The publication job runs only in +Rieke-OS, so a development tag cannot accidentally publish in epicTreeGUI. This +checkout has no `release-signing-public.pem`; production signing and publication +protection still need configuration. + +## One-click distribution target + +The current [Electron production specification](../design/electron-production-spec.md) +selects a complete signed Electron app, bundled Python/MySQL and electron-updater +as its sole desktop update authority. The [earlier gap map](../design/one-click-installer.md) +preserves the audit and comparison of alternatives. The Python manager +and source artifact described below remain the existing development mechanism. +See the [primary-source review](INSTALLER_PRIMARY_SOURCE_REVIEW.md) for packaging +and signing constraints. No desktop artifact was built during that planning pass. + +Users should download a self-contained desktop installer from GitHub Releases, +open it once, and thereafter launch the installed app normally. The installer +must contain Python and its locked packages, the pinned parser and compiled +utilities, the built React assets, the private MySQL runtime, and the Electron +lifetime owner/updater. The RSA manager/key below belong to source installations, +not a second desktop updater. Setup must run offline without Git, uv, +Node/npm, a compiler, Homebrew, Docker, or an existing Python installation. + +The current source artifact does not satisfy that contract: its Python runtime +is created on the user's computer, and its editable parser/venv paths cannot +simply be copied to another machine. The remaining packaging work is a relocatable +Python runtime with resolved parser imports, offline native-runtime preparation, +a native app entry point, and a signed/notarized macOS installer. Developer ID +signing/notarization credentials are separate from the updater's RSA signing key. +Validate the final installer on a clean machine without development tools and +exercise a real old-to-new automatic update before advertising one-click install. +Apple Silicon macOS is the only currently validated native artifact platform. + +### MATLAB is optional + +The web app does not launch MATLAB or require a MATLAB license/runtime. Its +Python backend writes `.mat` exports with NumPy/SciPy and reads `.ugm` masks. +MATLAB is needed only by users who choose to open the EpicTreeGUI export in +MATLAB. Core install, launch, import, browsing, tags, query, and update validation +must run without MATLAB. Licensed MATLAB validation belongs to the optional +EpicTreeGUI interoperability claim, rather than a prerequisite for installing or +shipping the core app. Continue running Python export/mask compatibility tests +in the normal suite. + ## Implemented contracts - `rieke-release.json`, frontend package version and npm lockfile version agree. @@ -24,6 +96,12 @@ install into themselves. A missing GitHub release is reported as unavailable. requires exclusive lifetime locks; managed chooser and detached project processes hold shared locks. Activation refuses incompatible database generations. App updates never perform implicit project migrations. +- Successful automatic checks start one background staging attempt per new + version per service session. Failed downloads can be retried in the panel. + Other services reuse only a completed receipt matching the signed manifest. + The stable manager applies prepared updates on the next launch when all + application locks are free. Workspace launchers created by a managed install + point to that manager instead of pinning a particular release directory. - Managed launch uses built frontend assets. Source/development launch still builds the frontend. Managed launch directly uses its Python service and needs no Node/npm, Git or Docker command. The previous version remains available for recovery. @@ -52,7 +130,9 @@ A maintainer must create an RSA release signing key in their chosen secret management system and commit only its public PEM as `release-signing-public.pem`. No private key or generated trust anchor is included by this change. Protect the `release-signing` GitHub environment and set its `RELEASE_SIGNING_PRIVATE_KEY` -secret. Review ownership and rotation procedures before distributing the key. +secret. Configure required reviewers on `release-publishing` to verify the +release-evidence gates below before public promotion. Review ownership and +rotation procedures before distributing the key. Publish the current reviewed application source first. The source and parser commit must be fetchable by a clean machine. The current dirty development tree @@ -63,17 +143,22 @@ is intentionally rejected by the release packager. PR CI runs frontend tests/build, Python workspace tests and coordinated-version validation. A separate Apple Silicon job prepares the private native runtime, checks full project readiness and runs real database lifecycle and transfer tests -without requiring a signing key or release tag. The manually dispatched -`workspace-release-candidate.yml` checks out -the requested reviewed version tag, exercises setup and tests on Apple Silicon, +without requiring a signing key or release tag. Pushing a `v` tag +triggers `workspace-release-candidate.yml`, which checks out +the reviewed version tag, exercises setup and tests on Apple Silicon, including real native MySQL lifecycle and native project transfer/copy tests, -builds a signed artifact and uploads it as a GitHub Actions artifact. It does not -publish a public GitHub Release. +builds a signed artifact and uploads it as a GitHub Actions artifact. After the +protected `release-publishing` environment approves promotion, a dependent job +publishes those exact artifacts as the latest stable GitHub Release. Manual +dispatch builds a candidate by default; its optional `publish` input requests +the same protected promotion. Existing release assets are never overwritten. Before promoting the candidate to a stable GitHub Release, require recorded passing evidence for real MySQL/DataJoint import/edit/export/restart, complete workspace transfer to a different path and machine, previous-to-current update -and recovery, active-worker shutdown, and licensed MATLAB handoff regressions. +and recovery, and active-worker shutdown. Licensed MATLAB handoff regressions are +required when advertising the optional EpicTreeGUI interoperability feature; +MATLAB is not a core app dependency. Mocked/unit-only tests do not satisfy those gates. A missing runner is not a pass. Only upload the exact signed artifact and `rieke-release-manifest.json` under its matching `v` GitHub Release tag. Linux is not an advertised artifact yet. @@ -90,8 +175,15 @@ python3 /path/to/RiekeOS/manager.py --installation /path/to/RiekeOS activate python3 /path/to/RiekeOS/manager.py --installation /path/to/RiekeOS launch ``` -The managed app can stage a signed update while running. Its result includes the -exact apply command. Close all chooser and project-service processes, then run: +The managed app automatically stages a new signed update while running. Close all +chooser and project-service processes, then launch normally through `manager.py` +or a workspace launcher created by the managed app. It applies the prepared +version before starting the chooser. No check/download/apply command is needed +for subsequent updates. Existing manager copies and old workspace launchers must +be upgraded once to gain this behavior; they are not rewritten in place by these +source changes. + +For diagnostics, an explicit wait-and-apply command remains available: ```sh python3 /path/to/RiekeOS/manager.py --installation /path/to/RiekeOS activate-and-launch @@ -107,3 +199,55 @@ service. The UI must not present this as implemented. Incompatible database updates likewise stay disabled until verified backup/migration/recovery exists. Key rotation and automatic recovery from post-activation startup failure are also not implemented; the previous release is retained, not silently restored. + + +## Electron desktop qualification + +The Electron candidate uses bundled Python, parser and native MySQL. Normal +launch, project creation, import and browsing require no Docker, external MySQL, +Node or MATLAB. An older Docker-backed source project is inspected before any +desktop service is started. Create a desktop copy in a new folder explicitly; +the one-time source snapshot may read an already-running source Docker database. +It never starts, stops or executes commands in Docker. Alternatively, prepare a +portable copy with the source installation and receive it in the desktop app. +The original source project is never silently converted in place. + +After packaging, run these suites against the packaged candidate: + +```sh +npm test --prefix desktop +npm test --prefix workspace-app +npm run test:e2e:updater --prefix desktop +npm run test:e2e --prefix desktop +npm run test:e2e:startup-failure --prefix desktop +python3 tools/desktop_artifact_e2e.py --installed 'desktop/dist/mac-arm64/Rieke OS.app' +``` + +The UI suite launches only scratch copies with isolated HOME and user data. It +keeps Electron sandbox and CSP enabled and tests the real packaged ASAR. OS +folder chooser return values are the explicit stubbed boundary. Set +`RIEKE_E2E_H5` to a private local recording to additionally test real active +import shutdown deferral. The scientific suite checks exact H5 sample values, +annotations, masks, query membership, downloaded JSON/SQLite/MAT exports, +restart and transfer through actual native services: + +```sh +python3 tools/desktop_scientific_e2e.py --recording /absolute/path/to/fixture.h5 +python3 tools/desktop_artifact_e2e.py --installed 'desktop/dist/mac-arm64/Rieke OS.app' --recording /absolute/path/to/fixture.h5 +``` + +Private recordings remain local and must never be attached to public evidence +or build resources. Receipts bind checks to the packaged runtime manifest and +artifact hashes. A failed receipt is retained as evidence, then the final suite +is repeated after fixes. The candidate workflow runs updater transport faults, +packaged UI and extracted-installer audits before inventorying a successful +candidate, and uploads failure evidence separately. + +The updater suite exercises the pinned library and real Electron HTTP transport +against a private fixture server. It covers malformed and unavailable metadata, +version rejection, checksum mismatch, interrupted downloads, unwritable cache +and unsigned candidates without authorizing a native installer. These checks +do not qualify signed Squirrel installation, notarization, cross-machine +Gatekeeper, or previous-to-current recovery. Those remain release gates when +Developer ID credentials and a second clean machine are available. Unsigned +local packages keep update installation disabled. diff --git a/docs/dev/scale-audit-2026-09-29/backend_index_probe.py b/docs/dev/scale-audit-2026-09-29/backend_index_probe.py new file mode 100644 index 0000000..89e6551 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/backend_index_probe.py @@ -0,0 +1,79 @@ +"""Disposable current disk-index probe; run with PYTHONPATH=python. + +No scientific data, MySQL connection, acquisition H5, or production cache is read. +Synthetic metadata comes from a lazy Mapping to avoid allocating all details. +""" +import argparse +from collections.abc import Mapping +import cProfile +import gc +import io +import json +from pathlib import Path +import platform +import pstats +import resource +import statistics +import tempfile +import time +from workspace_disk_index import DiskMetadataIndex + + +def run(count, parameter_fields, source_count, profile=False): + rows = [dict(epoch_uuid=f'e-{i}',cell_uuid=f'c-{i//100}',cell_label=f'Cell {i//100}', + date='2026-09-29',start_time=f'09/29/2026 12:00:{i%60:02d}:000000',cell_type='ON', + block_uuid=f'b-{i//20}',block_start_time=f'09/29/2026 12:00:{i%60:02d}:000000', + protocol_name='Synthetic',source_sha256=f's-{(i//100)%source_count}',group_uuid='g', + group_label='g',duration_seconds=1.,epoch_number=i%20+1) for i in range(count)] + sources = [{'source_sha256':f's-{i}'} for i in range(source_count)] + class Details(Mapping): + def __getitem__(self,key): + i=int(key[2:]) + return {'parameters':{f'axis{k}':(i//(k+1))%7 for k in range(parameter_fields)}, + 'metadata':{'cell':{'start_time':'09/29/2026 12:00:00:000000'}}} + def __len__(self): return count + def __iter__(self): return (r['epoch_uuid'] for r in rows) + result={'epochs':count,'parameter_fields':parameter_fields,'sources':source_count, + 'python':platform.python_version(),'fixture':'synthetic lazy details; no H5/SQL/browser IO', + 'measurements':[]} + def measure(name,fn,repeats=1): + timings=[];value=None + for _ in range(repeats): + started=time.perf_counter();value=fn();timings.append(time.perf_counter()-started) + item=dict(operation=name,seconds=timings,median_seconds=statistics.median(timings)) + result['measurements'].append(item) + return value + with tempfile.TemporaryDirectory(prefix='rieke-audit-index-') as folder: + path=Path(folder)/'metadata.sqlite' + index=measure('build',lambda:DiskMetadataIndex.build(path,rows,Details(),sources,'audit','project')) + result['fields']=len(index.catalog()['fields']);result['db_bytes']=path.stat().st_size + index=measure('open_verified',lambda:DiskMetadataIndex.open(path,'audit','project'),3) + measure('cached_catalog',index.catalog,3) + ids=[row['epoch_uuid'] for row in rows if int(row['epoch_uuid'][2:])%7==3] + measure('scoped_catalog_one_seventh',lambda:index.catalog(ids),3) + measure('low_cardinality_predicate',lambda:index.match({'field':'parameters/axis0','operator':'eq','value':3}),3) + measure('epoch_uuid_equality',lambda:index.match({'field':'epoch','operator':'eq','value':f'e-{count//2}'}),3) + measure('all_source_projections_lazy',lambda:[index.source_projection(s['source_sha256'],lazy_details=True) for s in sources],3) + result['detail_cache_entries']=len(index.details.cache) + if profile: + profiler=cProfile.Profile();profiler.enable();index.catalog(ids);profiler.disable() + output=io.StringIO();pstats.Stats(profiler,stream=output).strip_dirs().sort_stats('cumtime').print_stats(30) + result['scoped_catalog_profile']=output.getvalue() + profiler=cProfile.Profile();profiler.enable();index.match({'field':'epoch','operator':'eq','value':f'e-{count//2}'});profiler.disable() + output=io.StringIO();pstats.Stats(profiler,stream=output).strip_dirs().sort_stats('cumtime').print_stats(25) + result['epoch_equality_profile']=output.getvalue() + # Do not retain the list of all-source projections across cleanup. + del index + gc.collect() + rss=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + result['peak_rss_mib']=rss/(1024**2 if platform.system()=='Darwin' else 1024) + return result + + +if __name__=='__main__': + parser=argparse.ArgumentParser();parser.add_argument('--epochs',type=int,required=True) + parser.add_argument('--fields',type=int,required=True);parser.add_argument('--sources',type=int,required=True) + parser.add_argument('--profile',action='store_true');parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args();result=run(args.epochs,args.fields,args.sources,args.profile) + args.output.write_text(json.dumps(result,indent=2)+'\n') + print(json.dumps({key:value for key,value in result.items() if not key.endswith('_profile')},indent=2)) diff --git a/docs/dev/scale-audit-2026-09-29/backend_source_dispatch_probe.py b/docs/dev/scale-audit-2026-09-29/backend_source_dispatch_probe.py new file mode 100644 index 0000000..c2dd417 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/backend_source_dispatch_probe.py @@ -0,0 +1,50 @@ +"""Isolate ChainMap source dispatch during metadata-index generation rebuild. + +All rows, SQLite, and OS-stat files are disposable synthetic fixtures. +""" +from collections import ChainMap +from pathlib import Path +import json +import platform +import random +import statistics +import tempfile +import time +from unittest.mock import patch +import workspace_disk_index as disk +from workspace_disk_index import DiskMetadataIndex + + +def run(): + output={'fixture':'synthetic, no H5 or MySQL','epochs':1000,'cells':10, + 'python':platform.python_version(),'measurements':[]} + rows=[dict(epoch_uuid=f'e-{i}',cell_uuid=f'c-{i//100}',cell_label='Cell',date='2026-09-29', + source_sha256='s',protocol_name='Synthetic',block_uuid='b',group_uuid='g') for i in range(1000)] + details={row['epoch_uuid']:{'parameters':{'axis':i%7}} for i,row in enumerate(rows)} + ids=[row['epoch_uuid'] for row in rows] + random.Random(1).shuffle(ids) + with tempfile.TemporaryDirectory(prefix='rieke-source-dispatch-') as folder: + index=DiskMetadataIndex.build(Path(folder)/'index.sqlite',rows,details,[{'source_sha256':'s'}],'audit','project') + for scopes in (1,10,100,500): + memberships=[dict.fromkeys(ids[i::scopes]) for i in range(scopes)] + chain=ChainMap(*(disk._ScopedDetails(index.details,bucket) for bucket in memberships)) + start=time.perf_counter() + with patch.object(index,'_check',wraps=index._check) as checks: + for identity in ids: chain[identity] + calls=checks.call_count + elapsed=time.perf_counter()-start + output['measurements'].append(dict(source_scopes=scopes,lookup_seconds=elapsed, + index_stat_checks=calls,notes='Mock call recording adds timing overhead; structural call count is exact.')) + # Timings without instrumentation; same detail cache bounded to 64. + elapsed=[] + for repeat in range(3): + start=time.perf_counter() + for identity in ids: chain[identity] + elapsed.append(time.perf_counter()-start) + output['measurements'][-1].update(uninstrumented_seconds=elapsed,median_seconds=statistics.median(elapsed)) + return output + + +if __name__=='__main__': + result=run();path=Path('docs/dev/scale-audit-2026-09-29/backend-source-dispatch.json') + path.write_text(json.dumps(result,indent=2)+'\n');print(json.dumps(result,indent=2)) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_catalog_identity.py b/docs/dev/scale-audit-2026-09-29/benchmark_catalog_identity.py new file mode 100644 index 0000000..6c69c2d --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_catalog_identity.py @@ -0,0 +1,69 @@ +"""Measure the complete ownership verifier with synthetic indexed SQL doubles. + +No database, file parsing or waveform reads. The fake semi-join uses a hash +membership lookup so it does not introduce a quadratic test-only nested loop. +""" +import argparse +import hashlib +import json +from pathlib import Path +import resource +import time + +import workspace_catalog_identity as validator +from test_workspace_catalog_identity import Rows, fixture + + +class IndexedRows(Rows): + def __and__(self, restriction): + conditions = restriction.rows if isinstance(restriction, Rows) else restriction if isinstance(restriction, list) else [restriction] + groups = {} + for condition in conditions: + keys = tuple(sorted(condition)) + groups.setdefault(keys, set()).add(tuple(condition[key] for key in keys)) + selected = [row for row in self.rows if any(tuple(row.get(key) for key in keys) in values + for keys, values in groups.items())] + return IndexedRows(selected, self.fetches, self.name) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs', type=int, default=100000) + parser.add_argument('--output', type=Path, required=True) + args = parser.parse_args() + if args.epochs < 2 or args.epochs % 2: + parser.error('epochs must be positive and even') + if args.output.exists(): + parser.error('Choose a new output file; preserve earlier evidence') + path = Path(validator.__file__) + before = hashlib.sha256(path.read_bytes()).hexdigest() + started = time.perf_counter() + source, catalog, rows, fetches = fixture(args.epochs // 2) + for name, relation in vars(catalog).items(): + setattr(catalog, name, IndexedRows(relation.rows, relation.fetches, relation.name)) + construction = time.perf_counter() - started + started = time.perf_counter() + counts = validator.validate_catalog_identity(source, catalog, 7) + elapsed = time.perf_counter() - started + fetch_count = len(fetches) + rows['EpochGroup'][0]['parent_id'], rows['EpochGroup'][1]['parent_id'] = rows['EpochGroup'][1]['parent_id'], rows['EpochGroup'][0]['parent_id'] + try: + validator.validate_catalog_identity(source, catalog, 7) + except validator.CatalogIdentityConflict as error: + rejection = error.conflict['kind'] + else: + raise AssertionError('Swapped-parent corruption accepted') + after = hashlib.sha256(path.read_bytes()).hexdigest() + report = dict(epochs=args.epochs, counts=counts, fixture_seconds=construction, + validation_seconds=elapsed, table_fetches=fetch_count, + peak_process_rss_native_units=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss, + rss_units='bytes on macOS, KiB on Linux; entire process including fixture and deep-copy fetches', + swapped_parent_rejection=rejection, helper_sha256=before, source_unchanged=before == after, + environment='Synthetic indexed relational doubles with deep-copy fetch; no native SQL/H5 parsing; one timed sample') + assert before == after and counts['Epoch'] == args.epochs and rejection == 'catalog_parent' + args.output.write_text(json.dumps(report, indent=2) + '\n') + print(json.dumps(report, indent=2)) + + +if __name__ == '__main__': + main() diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_curation_vocabulary.py b/docs/dev/scale-audit-2026-09-29/benchmark_curation_vocabulary.py new file mode 100644 index 0000000..5a6e770 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_curation_vocabulary.py @@ -0,0 +1,36 @@ +import hashlib,json,time,uuid +from pathlib import Path +from types import SimpleNamespace +from test_workspace_state_generation import NativeGenerationTests as T +from workspace_recovery_generation import RecoveryTracker +from workspace_curation_vocabulary import CurationVocabulary +paths=[Path('python')/name for name in ('workspace_curation_vocabulary.py','workspace_shared_tag_index.py','workspace_recovery_generation.py')] +hashes=lambda:{str(p):hashlib.sha256(p.read_bytes()).hexdigest() for p in paths} +report={'epochs':100000,'protocols':2,'tags_per_record':5,'scope':'Isolated native vocabulary: canonical JSON curation, generation triggers and derived SQLite; excludes metadata/shared/recovery mirror workloads','hashes_before':hashes()} +T.setUpClass();index=None +try: + c=T.connection;p=str(uuid.uuid4());protocols=[str(uuid.uuid4()) for _ in range(2)];epochs=[str(uuid.UUID(int=i+1)) for i in range(100000)] + started=time.perf_counter() + with c._conn.cursor() as cur: + for position,protocol in enumerate(protocols): + tags=json.dumps([f'dataset:{position}']+[f'dataset-tag:{i}' for i in range(1,5)]) + for offset in range(0,len(epochs),1000): + cur.executemany('INSERT INTO recording_workspace.curation VALUES (%s,%s,%s,%s,1)',[(p,protocol,e,tags) for e in epochs[offset:offset+1000]]) + report['seed_seconds']=time.perf_counter()-started + tracker=RecoveryTracker(c,p).bootstrap();assert tracker.ready,tracker.reason + index=CurationVocabulary(SimpleNamespace(project_uuid=p,dj=SimpleNamespace(conn=lambda:c)),tracker) + def status():return dict(c.query("SHOW SESSION STATUS WHERE Variable_name IN ('Handler_read_next','Handler_read_key','Rows_sent','Bytes_sent')").fetchall()) + def measure(label): + before=status();t=time.perf_counter();result=index.suggestions('dataset',30);elapsed=time.perf_counter()-t;after=status() + report[label]={'seconds':elapsed,'sql':{k:int(after[k])-int(before[k]) for k in before},'stats':dict(index.stats)} + assert len(result['tags'])==6 and all(x['count']==100000 for x in result['tags']),result + measure('cold');measure('warm') + c.query('UPDATE recording_workspace.curation SET tags=JSON_ARRAY_APPEND(tags,%s,%s) WHERE project_uuid=%s AND protocol_uuid=%s AND epoch_uuid=%s',('$','edited',p,protocols[0],epochs[0])) + measure('after_edit') + assert index.suggestions('edited',30)['tags']==[{'tag':'edited','count':1}] + report['storage']=index.storage_stats();report['hashes_after']=hashes();report['passed']=report['hashes_before']==report['hashes_after'] + print(json.dumps(report,indent=2),flush=True) + Path('docs/dev/scale-audit-2026-09-29/curation-vocabulary-200000-scalar-keyset.json').write_text(json.dumps(report,indent=2)+'\n') +finally: + if index:index.close() + T.tearDownClass() diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_dense_protocol_state.py b/docs/dev/scale-audit-2026-09-29/benchmark_dense_protocol_state.py new file mode 100644 index 0000000..d6b55ad --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_dense_protocol_state.py @@ -0,0 +1,73 @@ +"""Dense saved-curation revision fallback, disposable100k SQL-double project.""" +import argparse +import json +from pathlib import Path +import tempfile +from unittest.mock import patch + +from benchmark_service_scale import fixture,Details +from benchmark_epoch_pages import measure +from workspace_disk_index import DiskMetadataIndex +from workspace_service import WorkspaceService +from test_workspace_api import WorkspaceAPITests + + +def run(count): + api=WorkspaceAPITests();api.setUp() + try: + service,protocol=fixture(count) + service.project['project_uuid']=api.service.project['project_uuid'] + with tempfile.TemporaryDirectory(prefix='rieke-dense-state-') as folder: + index=DiskMetadataIndex.build(Path(folder)/'index.sqlite',service.rows,Details(service.rows), + service.sources,'dense-state-benchmark',service.project['project_uuid']) + target=api.service + target.__class__=WorkspaceService + for name in ('rows','cells','sources','_fingerprints'): + setattr(target,name,getattr(service,name)) + target.disk_index,target.details=index,index.details + target.protocols={target.protocol_id:service.protocols[protocol]} + target.protocols[target.protocol_id]['result']['protocol_uuid']=target.protocol_id + api.curation.rows.extend({'project_uuid':target.project['project_uuid'], + 'protocol_uuid':target.protocol_id,'epoch_uuid':key,'included':True, + 'tags':['checked'],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':target._fingerprints[key]} for key in target.rows) + reader=api.app.extensions['protocol_state_reader'] + target.epoch_page(target.protocol_id,limit=60) + path=api.base+'/epochs?limit=60' + read_counts=[] + def request(): + before=len(api.curation.read_log) + response=api.client.get(path) + assert response.status_code==200,response.get_json() + read_counts.append(len(api.curation.read_log)-before) + return response.get_json() + def uncached(protocol,ids): + result,states,revision=reader.full_state(protocol) + return {key:states[key] for key in ids},revision,result.get('dataset_binding',{}).get('version',0) + with patch.object(reader,'read_selected',side_effect=uncached): + legacy,old=measure(request) + legacy_reads=read_counts[:];read_counts.clear() + cold,new=measure(request,1) + cold_reads=read_counts[:];read_counts.clear() + repeated,again=measure(request) + assert old==new==again + return {'epochs':count,'saved_curation_rows':count,'tags_per_row':1, + 'scope':'Actual Flask GET plus JSON, real sealed SQLite metadata index, transactional SQL-double curation table with one saved tag on every epoch. Excludes real MySQL/network, browser, shared annotations and waveform I/O.', + 'legacy_full_revision_http':legacy,'cache_attempt_cold_http':cold, + 'cache_attempt_repeated_http':repeated,'full_curation_reads':{ + 'legacy_samples':legacy_reads,'cold_sample':cold_reads,'repeated_samples':read_counts}, + 'retained_revision_scopes':len(reader.cache), + 'estimated_retained_revision_bytes':sum(item['size'] for item in reader.cache.values()), + 'exact_legacy_response_parity':True} + finally: + api.doCleanups() + + +if __name__=='__main__': + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs',type=int,default=100000) + parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args() + result=run(args.epochs) + args.output.write_text(json.dumps(result,indent=2)+'\n') + print(json.dumps(result,indent=2),flush=True) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_epoch_pages.py b/docs/dev/scale-audit-2026-09-29/benchmark_epoch_pages.py new file mode 100644 index 0000000..e54d67e --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_epoch_pages.py @@ -0,0 +1,84 @@ +"""Disposable exact before/after protocol-page benchmark, including Flask overhead. + +Uses the existing scale fixture and real sealed SQLite index. HTTP routes use +transactional SQL doubles with no saved tags. No real catalog or H5 data is used. +""" +import argparse +import gc +import json +from pathlib import Path +import statistics +import tempfile +import time +from unittest.mock import patch + +from benchmark_service_scale import fixture, Details +from workspace_disk_index import DiskMetadataIndex +from test_workspace_api import WorkspaceAPITests + + +def legacy_page(service, protocol, filters=None, offset=0, limit=100, anchor_uuid=None): + rows=service.filtered_rows(protocol,filters) + if anchor_uuid is not None: + position=next(index for index,row in enumerate(rows) if row['epoch_uuid']==anchor_uuid) + offset=position//limit*limit + return {'total':len(rows),'offset':offset,'limit':limit,'epochs':rows[offset:offset+limit]} + + +def measure(operation,repeats=3): + samples=[] + for _ in range(repeats): + gc.collect() + started=time.perf_counter();result=operation();samples.append(time.perf_counter()-started) + return {'median_seconds':statistics.median(samples),'samples_seconds':samples},result + + +def run(count): + service,protocol=fixture(count) + with tempfile.TemporaryDirectory(prefix='rieke-epoch-page-benchmark-') as folder: + started=time.perf_counter() + index=DiskMetadataIndex.build(Path(folder)/'index.sqlite',service.rows,Details(service.rows), + service.sources,'epoch-page-benchmark',service.project['project_uuid']) + service.disk_index,service.details=index,index.details + report={'epochs':count,'index_build_seconds':time.perf_counter()-started, + 'scope':'Synthetic one-protocol project. Real sealed SQLite index; no waveform or lab catalog I/O. Flask measurements include JSON and current global query-revision calculation but use SQL doubles with empty saved-curation tables, so exclude database/network latency and dense annotation cost.'} + for label,filters in [('all',None),('one_cell',{'cell_uuid':next(iter(service.cells))})]: + before,old=measure(lambda:legacy_page(service,protocol,filters,limit=60)) + cold,new=measure(lambda:service.epoch_page(protocol,filters,limit=60),1) + after,new=measure(lambda:service.epoch_page(protocol,filters,limit=60)) + assert old==new + report[label]={'legacy':before,'new_cold':cold,'new_warm':after,'exact_page_parity':True} + # Use the actual production Flask route to expose its remaining full + # state/revision computation, separately from service-only timings. + api=WorkspaceAPITests();api.setUp() + try: + target=api.service + for name in ('rows','details','cells','sources','_fingerprints','disk_index'): + setattr(target,name,getattr(service,name)) + target.protocols={target.protocol_id:service.protocols[protocol]} + target.protocols[target.protocol_id]['result']['protocol_uuid']=target.protocol_id + path=api.base+'/epochs?limit=60' + def get_page(): + response=api.client.get(path) + assert response.status_code==200,response.get_json() + return response.get_json() + with patch.object(target,'epoch_page',side_effect=lambda *args,**kwargs:legacy_page(target,*args,**kwargs)): + before,old=measure(get_page) + after,new=measure(get_page) + assert old==new + report['flask_page_empty_curation_sql_double']={'legacy':before,'new':after,'exact_response_parity':True} + finally: + api.doCleanups() + report['retained_epoch_scopes']={'count':len(service._epoch_page_cache[1]), + 'estimated_entry_bytes':sum(item[2] for item in service._epoch_page_cache[1].values())} + return report + + +if __name__=='__main__': + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs',type=int,default=100000) + parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args() + report=run(args.epochs) + args.output.write_text(json.dumps(report,indent=2)+'\n') + print(json.dumps(report,indent=2),flush=True) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_native_dense_tags.py b/docs/dev/scale-audit-2026-09-29/benchmark_native_dense_tags.py new file mode 100644 index 0000000..c319c49 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_native_dense_tags.py @@ -0,0 +1,288 @@ +"""Native dense-tag API workload in a fresh disposable project. + +Actual MySQL, triggers, SQLite indexes, Flask routes and save/checkpoint hooks. +Acquisition metadata is synthetic; no H5 parsing/waveform/NAS/browser claim. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import pstats +from pathlib import Path +import resource +import statistics +import tempfile +import time +import traceback +import uuid + +from benchmark_service_scale import fixture, Details, uid +from recording_workspace import connect, workspace_tables +from workspace_projects import create_project +from workspace_native_mysql import ensure_native_database, stop_native_database +from workspace_disk_index import DiskMetadataIndex +from workspace_api import create_app + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[2] +FILES = ['workspace_api.py', 'workspace_service.py', 'workspace_curation.py', + 'workspace_protocol_state.py', 'workspace_state_generation.py', + 'workspace_annotations.py', 'workspace_shared_tag_index.py', 'workspace_state_snapshot.py', + 'workspace_recovery_store.py', 'workspace_recovery_generation.py', 'workspace_curation_vocabulary.py'] + + +def hashes(): + return {name: hashlib.sha256((ROOT / 'python' / name).read_bytes()).hexdigest() for name in FILES} + + +def tags_for(ordinal, profile, size, *, cell=False): + initial = (['inherited', f'cell-bucket:{ordinal % 13}', f'profile:{profile}', 'same', 'cell-tag'] if cell else + ['all', f'bucket:{ordinal % 97}', 'ON' if ordinal % 2 == 0 else 'on', + 'é' if ordinal % 3 == 0 else 'e\u0301', f'profile:{profile}']) + return initial[:size] + [f'extra:{profile}:{index}' for index in range(len(initial), size)] + + +def percentiles(values): + ordered = sorted(values) + return {'samples_seconds': values, 'p50_seconds': statistics.median(values), + 'p95_seconds': ordered[max(0, math.ceil(.95 * len(ordered)) - 1)], + 'max_seconds': max(values)} + + +def disk_bytes(path): + files = [path] if path.is_file() else [p for p in path.rglob('*') if p.is_file() and not p.is_symlink()] + return {'apparent_bytes': sum(p.stat().st_size for p in files), + 'allocated_bytes': sum(p.stat().st_blocks * 512 for p in files), 'files': len(files)} + + +def run(args, report): + app = None; dj = None + with tempfile.TemporaryDirectory(prefix='rieke-native-dense-tags-') as directory: + root = Path(create_project(Path(directory) / 'projects', 'Disposable dense tag benchmark')['path']) + try: + ensure_native_database(root) + dj = connect({'kind': 'native-project'}, project_dir=root) + service, protocol = fixture(args.epochs) + service.project_dir = root + service.project = json.loads((root / 'project.json').read_text()) + service.config = json.loads((root / 'catalog.json').read_text()) + service.dj = dj + other = uid(-3) + service.protocols[other] = copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid'] = other + service.protocols[other]['result']['protocol_uuid'] = other + for value in service.protocols.values(): + value['definition']['project_uuid'] = service.project['project_uuid'] + value['definition']['query'] = {'version': 1, 'all': [ + {'field': 'EpochBlock.protocol_name', 'operator': 'eq', 'value': 'Synthetic'}]} + index = DiskMetadataIndex.build(root / 'cache' / 'dense.sqlite', service.rows, Details(service.rows), + service.sources, 'native-dense-synthetic-acquisition', service.project['project_uuid']) + service.disk_index = index; service.details = index.details + Project, _, _, _ = workspace_tables(dj) + Project.insert1({'project_uuid': service.project['project_uuid'], 'name': service.project['name'], 'directory': str(root)}) + app = create_app(root, ROOT / '.rieke-runtime/retinanalysis', service=service) + assert service._recovery_tracker.ready, service._recovery_tracker.reason + tracker = app.extensions['state_generation'] + assert tracker.ready, tracker.reason + assert tracker.token(protocol) is not None, tracker.reason + report['mysql_version'] = dj.conn().query('SELECT VERSION()').fetchone()[0] + store = app.extensions['curation_store']; shared = app.extensions['shared_annotations'] + authors = [uid(-100 - i) for i in range(args.profiles)] + now = dt.datetime(2026, 6, 11, 12) + project_id = service.project['project_uuid'] + started = time.perf_counter() + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid': project_id, 'profile_uuid': author, + 'display_name': f'Scientist {p}', 'created_at': now, 'created_by': 'native benchmark'} + for p, author in enumerate(authors)]) + batch = [] + for kind, identities in (('epoch', service.rows), ('cell', service.cells)): + for ordinal, identity in enumerate(identities): + for profile, author in enumerate(authors): + batch.append({'project_uuid': project_id, 'target_kind': kind, 'target_uuid': identity, + 'profile_uuid': author, 'tags': tags_for(ordinal, profile, args.tags, cell=kind == 'cell'), + 'author_name': f'Scientist {profile}', 'revision': 1, 'updated_at': now}) + if len(batch) == 500: + shared.Annotation.insert(batch); batch.clear() + if batch: shared.Annotation.insert(batch); batch.clear() + for position, current_protocol in enumerate((protocol, other)): + dataset_tags = [f'dataset:{position}'] + [f'dataset-tag:{i}' for i in range(1, args.tags)] + for identity in service.rows: + batch.append({'project_uuid': project_id, 'protocol_uuid': current_protocol, + 'epoch_uuid': identity, 'included': True, 'tags': dataset_tags, + 'review_state': 'unreviewed', 'revision': 1, + 'metadata_fingerprint': service._fingerprints[identity]}) + if len(batch) == 500: store.Curation.insert(batch); batch.clear() + if batch: store.Curation.insert(batch); batch.clear() + report['seed_seconds'] = time.perf_counter() - started + report['shared_rows'] = (len(service.rows) + len(service.cells)) * args.profiles + report['dataset_curation_rows'] = 2 * args.epochs + print('Native tags seeded', flush=True) + from workspace_state_snapshot import save as save_recovery + started = time.perf_counter() + report['seed_checkpoint'] = save_recovery(root, dj.conn(), service=service) + report['seed_checkpoint']['seconds'] = time.perf_counter() - started + print('Seed recovery checkpoint durable', flush=True) + client = app.test_client(); base = f'/api/protocols/{protocol}' + headers = {'X-Workspace-Request': '1', 'Origin': 'http://localhost:8766'} + report['operations'] = [] + + def sql_status(): + return {key: int(value) for key, value in dj.conn().query( + "SHOW SESSION STATUS WHERE Variable_name IN ('Rows_sent','Bytes_sent','Questions')").fetchall()} + + def get(path, query=None): + response = client.get(path, query_string=query) + value = response.get_json() + assert response.status_code == 200, (response.status_code, value) + return value + + def measure(name, callback, repeat=None): + durations = []; sql = []; result = None + profile = cProfile.Profile() if args.profile and any(value in name for value in ('summary', 'overview', 'suggestions')) else None + for _ in range(args.samples if repeat is None else repeat): + before = sql_status(); start = time.perf_counter() + if profile is not None: profile.enable() + result = callback() + if profile is not None: profile.disable() + durations.append(time.perf_counter() - start) + after = sql_status(); sql.append({key: after[key] - before[key] for key in before}) + record = {'name': name, **percentiles(durations), 'sql_session_deltas': sql} + if profile is not None: + profile_path = args.output.with_name(args.output.stem + '.' + name + '.prof') + profile.dump_stats(str(profile_path)) + stats = pstats.Stats(profile) + record['profile'] = [{'file': key[0], 'line': key[1], 'function': key[2], + 'primitive_calls': value[0], 'calls': value[1], 'own_seconds': value[2], + 'cumulative_seconds': value[3]} for key, value in + sorted(stats.stats.items(), key=lambda item: item[1][3], reverse=True)[:60]] + report['operations'].append(record) + print(json.dumps({'operation': name, 'p50': record['p50_seconds'], 'p95': record['p95_seconds']}), flush=True) + return result + + page = measure('page_cold', lambda: get(base + '/epochs', {'limit': 60}), 1) + assert len(page['epochs']) == min(60, args.epochs) and page['total'] == args.epochs + for row in page['epochs']: + ordinal = service.rows[row['epoch_uuid']]['synthetic_index'] + expected = sorted((tag, authors[p]) for p in range(args.profiles) for tag in tags_for(ordinal, p, args.tags)) + actual = sorted((item['tag'], item['profile_uuid']) for item in row['annotations']['epoch_tags']) + assert actual == expected + assert len(row['curation']['tags']) == args.tags + measure('page_warm', lambda: get(base + '/epochs', {'limit': 60})) + for tag, check in [('ON', lambda i: i % 2 == 0), ('on', lambda i: i % 2 != 0), + ('bucket:7', lambda i: i % 97 == 7), ('inherited', lambda i: True)]: + expected = [key for key, row in service.rows.items() if check(row['synthetic_index'])] + result = measure('filter_cold_' + tag, lambda tag=tag: get(base + '/epochs', {'limit': 60, 'tag': tag}), 1) + assert result['total'] == len(expected), (tag, result['total'], len(expected)) + assert [row['epoch_uuid'] for row in result['epochs']] == expected[:60] + measure('filter_warm_' + tag, lambda tag=tag: get(base + '/epochs', {'limit': 60, 'tag': tag})) + measure('protocol_summary_after_tagged_load', lambda: get(base), 1) + measure('overview_after_tagged_load', lambda: get('/api/overview'), 1) + measure('dataset_tag_suggestions_cold', lambda: get('/api/tags', {'q': 'dataset', 'limit': 30}), 1) + measure('dataset_tag_suggestions_warm', lambda: get('/api/tags', {'q': 'dataset', 'limit': 30}), 3) + identity = next(iter(service.rows)); revision = 1 + for iteration in range(args.edits): + current = get(base + '/epochs', {'limit': 1}) + body = {'epoch_uuids': [identity], 'query_revision': current['query_revision'], + 'expected_revisions': {identity: revision}, 'expected_binding_version': 0, + 'changes': {'tags_add': [f'edited:{iteration}']}} + def edit(): + response = client.post(base + '/curation', json=body, headers=headers) + assert response.status_code == 200, (response.status_code, response.get_json()) + return response.get_json() + measure('edit_with_durable_backup_' + str(iteration), edit, 1) + revision += 1 + result = measure('first_page_after_edit_' + str(iteration), lambda: get(base + '/epochs', {'limit': 60}), 1) + assert result['epochs'][0]['curation']['revision'] == revision + assert f'edited:{iteration}' in result['epochs'][0]['curation']['tags'] + measure('protocol_summary_after_edit_' + str(iteration), lambda: get(base), 1) + measure('overview_after_edit_' + str(iteration), lambda: get('/api/overview'), 1) + measure('dataset_tag_suggestions_after_edit_' + str(iteration), + lambda: get('/api/tags', {'q': 'dataset', 'limit': 30}), 1) + for iteration in range(args.edits): + body = {'target_kind': 'epoch', 'target_uuids': [identity], 'profile_uuid': authors[0], + 'tags_add': [f'shared-edited:{iteration}'], 'expected_revisions': {identity: iteration + 1}} + def shared_edit(): + response = client.post('/api/annotations', json=body, headers=headers) + assert response.status_code == 200, (response.status_code, response.get_json()) + return response.get_json() + measure('shared_edit_with_durable_backup_' + str(iteration), shared_edit, 1) + result = measure('shared_filter_after_edit_' + str(iteration), lambda: get(base + '/epochs', + {'limit': 60, 'tag': f'shared-edited:{iteration}'}), 1) + assert result['total'] == 1 and result['epochs'][0]['epoch_uuid'] == identity + measure('shared_summary_after_edit_' + str(iteration), lambda: get(base), 1) + report['shared_index_stats'] = getattr(getattr(shared, '_shared_tag_index', None), 'stats', None) + vocabulary = getattr(store, '_curation_vocabulary_index', None) + report['curation_vocabulary_stats'] = getattr(vocabulary, 'stats', None) + if vocabulary is not None: + report['curation_vocabulary_storage'] = vocabulary.storage_stats() + index = getattr(shared, '_shared_tag_index', None) + index_path = getattr(index, 'path', None) + report['storage'] = {'project': disk_bytes(root), 'native_database': disk_bytes(root / 'database'), + 'source_metadata_index': disk_bytes(root / 'cache'), 'recovery': disk_bytes(root / 'backups')} + if index_path is not None: + report['storage']['shared_tag_index'] = disk_bytes(Path(index_path)) + if index is not None: + report['storage']['shared_tag_index_sqlite'] = index.storage_stats() + report['storage']['sql_tables'] = dj.conn().query( + "SELECT TABLE_NAME,TABLE_ROWS,DATA_LENGTH,INDEX_LENGTH,DATA_FREE FROM information_schema.tables " + "WHERE TABLE_SCHEMA='recording_workspace' ORDER BY TABLE_NAME", as_dict=True).fetchall() + report['storage']['note'] = 'SQL row/byte estimates may lag; filesystem apparent and allocated totals include native redo/preallocation. Synthetic acquisition has no real waveform-size denominator.' + report['oracle_passed'] = True + finally: + if app is not None: + shared = app.extensions.get('shared_annotations') + index = getattr(shared, '_shared_tag_index', None) + if index is not None: index.close() + lock = app.extensions.get('app_state_session_lock') + if lock is not None: lock.close() + if dj is not None: dj.conn().close() + stop_native_database(root) + report['owned_runtime_stopped'] = True + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs', type=int, default=1000) + parser.add_argument('--tags', type=int, choices=(5, 20), default=5) + parser.add_argument('--profiles', type=int, default=3) + parser.add_argument('--samples', type=int, default=20) + parser.add_argument('--edits', type=int, default=3) + parser.add_argument('--output', type=Path, required=True) + parser.add_argument('--profile', action='store_true', help='Profile summary, overview and suggestion operations; timings include profiler overhead') + parser.add_argument('--mysql-runtime-root', type=Path, + help='Verified external runtime for copied-source validation; no live database reuse') + args = parser.parse_args() + if args.output.exists(): parser.error('Choose a new receipt path') + if args.mysql_runtime_root is not None: + from workspace_mysql_runtime import _probe, runtime_spec + import workspace_native_mysql as native + runtime = _probe(args.mysql_runtime_root.resolve(strict=True), runtime_spec(ROOT)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld', 'mysql', 'mysqldump'}: + raise ValueError('Unsupported external native executable') + return Path(runtime[name]) + native.native_binary = runtime_binary + report = {'epochs': args.epochs, 'tags_per_record': args.tags, 'profiles': args.profiles, + 'protocols': 2, 'source_hashes_before': hashes(), 'release_ready': False, + 'external_mysql_runtime': str(args.mysql_runtime_root) if args.mysql_runtime_root else None, + 'scope': 'Actual native MySQL + production Flask/save hooks + sealed SQLite synthetic metadata; excludes physical H5 parsing, waveform/NAS I/O and browser rendering.'} + try: + run(args, report) + except Exception as error: + report['error'] = {'type': type(error).__name__, 'message': str(error), 'traceback': traceback.format_exc()} + print(traceback.format_exc(), flush=True) + report['source_hashes_after'] = hashes() + report['source_changed_during_run'] = [name for name, value in report['source_hashes_before'].items() + if value != report['source_hashes_after'][name]] + report['peak_rss_bytes_macos'] = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed'] = bool(report.get('oracle_passed')) and not report['source_changed_during_run'] + args.output.write_text(json.dumps(report, indent=2) + '\n') + return 0 if report['passed'] else 1 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py b/docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py new file mode 100644 index 0000000..7bc0fab --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py @@ -0,0 +1,465 @@ +"""Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and each version's save hooks +are used. Native SQL commits are checked immediately; any background recovery +mirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=5);ap.add_argument('--targets',default='tag10_then10_filter20_and_cell_epoch_hierarchy') + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true') + ap.add_argument('--page-cells',action='store_true',default=True) + args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<200 or args.samples<1:ap.error('Use at least200 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + import importlib.util + from workspace_annotations import SharedAnnotations,annotation_tables + from workspace_curation import curation_tables + sqlite_tag_calls={'membership_index':0,'refresh':0} + original_membership=getattr(SharedAnnotations,'_membership_index',None) + if original_membership is not None: + def observed_membership(*args,**kwargs): + sqlite_tag_calls['membership_index']+=1 + return original_membership(*args,**kwargs) + SharedAnnotations._membership_index=observed_membership + if importlib.util.find_spec('workspace_shared_tag_index') is not None: + from workspace_shared_tag_index import SharedTagIndex + original_refresh=SharedTagIndex.refresh + def observed_refresh(*args,**kwargs): + sqlite_tag_calls['refresh']+=1 + return original_refresh(*args,**kwargs) + SharedTagIndex.refresh=observed_refresh + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[], + 'page_cells':True,'target_specification':args.targets,'baseline_harness_sha256':digest(Path(__file__).with_name('benchmark_scientist_tag_workflow.py'))} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-native-tag-sequence-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + service.manifests={item['source_sha256']:{'source_path':'/synthetic/'+item['filename']} for item in service.sources} + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + # Construct only canonical fixture tables before application + # startup. Normal startup then performs the actual populated + # native lookup/dictionary migration once; all timed writes + # retain the installed product triggers. + ProfileTable,AnnotationTable=annotation_tables(dj) + CurationTable,_=curation_tables(dj) + derived_tables=dj.conn().query("SELECT table_name FROM information_schema.tables WHERE table_schema='recording_workspace' AND table_name IN ('app_shared_tag_lookup','app_shared_tag_dictionary','app_shared_tag_authors')").fetchall() + assert not derived_tables,derived_tables + authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + ProfileTable.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:AnnotationTable.insert(batch);batch=[] + if batch:AnnotationTable.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:CurationTable.insert(batch);batch=[] + if batch:CurationTable.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + log(json.dumps({'stage':'populated_native_startup','epochs':args.epochs,'canonical_seed_seconds':report['seed_seconds']})) + began=time.perf_counter() + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + report['populated_native_startup_seconds']=time.perf_counter()-began + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'] + report['fixture_construction']={'strategy':'canonical seed before normal app startup and populated native migration', + 'native_derived_tables_absent_during_seed':not derived_tables, + 'canonical_shared_records':(args.epochs+len(service.cells))*3, + 'canonical_curation_records':args.epochs*2, + 'product_triggers_disabled_during_timed_operations':False} + check('populated_native_migration_ready_before_timed_operations',service.annotation_preparation.get('status')=='ready' and service.annotation_preparation.get('storage')=='native_sql') + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + + + import inspect + import threading + app_db_lock=inspect.getclosurevars(app.view_functions['annotation_batch_read']).nonlocals['db_lock'] + report['native_lookup_startup_preparation']=copy.deepcopy(getattr(service,'annotation_preparation',None)) + first=ids[:10];second=ids[100:110];selected=first+second;cell=service.rows[first[0]]['cell_uuid'] + children=tuple(key for key in ids if service.rows[key]['cell_uuid']==cell) + assert len(children)==100 and service.rows[second[0]]['cell_uuid']!=cell + epoch_marker='sequence-selected';cell_marker='sequence-cell' + epoch_predicate={'all':[rule(epoch_marker,'epoch')]} + cell_predicate={'all':[rule(cell_marker,'cell')]} + hierarchy={'all':[rule(cell_marker,'cell'),rule(epoch_marker,'epoch')]} + model={(kind,key,p):set() for kind,keys in [('epoch',selected),('cell',(cell,))] for key in keys for p in range(3)} + revisions={key:1 for key in model} + report['selected_epoch_uuids']={'first10':first,'second10':second,'cell':cell,'cell_children':children} + report['backup_receipts']=[] + def sql_status(): + with app_db_lock:return {key:int(value) for key,value in dj.conn().query("SHOW SESSION STATUS WHERE Variable_name IN ('Bytes_sent','Questions')").fetchall()} + def request(method,path,*,query=None,body=None): + response=client.get(path,query_string=query) if method=='GET' else client.post(path,json=body,headers=headers) + value=response.get_json() + if response.status_code!=200:raise AssertionError((method,path,response.status_code,value)) + return value + def measure(name,callback): + before=sql_status();began=time.perf_counter();value=callback();elapsed=time.perf_counter()-began;after=sql_status() + samples.setdefault(name,[]).append(elapsed);sql_samples.setdefault(name,[]).append({key:after[key]-before[key] for key in before}) + return value,elapsed + def wanted_tags(kind,key,p): + ordinal=ordinals[key] if kind=='epoch' else cell_ordinals[key] + return sorted([*tags(ordinal,p,cell=kind=='cell'),*model.get((kind,key,p),())]) + def validate_target(row,kind,key): + assert row['target_uuid']==key and row['target_kind']==kind + assert row['revisions']=={author:revisions.get((kind,key,p),1) for p,author in enumerate(authors)} + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['tags'])==sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,key,p)) + def preflight(label,keys,p,*,timed=True): + call=lambda:request('POST','/api/annotations/read',body={'target_kind':'epoch','target_uuids':list(keys)}) + value,_=measure(label,call) if timed else (call(),0) + assert set(value['targets'])==set(keys) + for key,row in value['targets'].items():validate_target(row,'epoch',key) + return {key:value['targets'][key]['revisions'][authors[p]] for key in keys} + def change(label,kind,keys,p,marker,add,expected=None,*,timed=True): + body={'target_kind':kind,'target_uuids':list(keys),'profile_uuid':authors[p], + 'tags_add':[marker] if add else [],'tags_remove':[] if add else [marker], + 'expected_revisions':expected or {key:revisions[(kind,key,p)] for key in keys}} + call=lambda:request('POST','/api/annotations',body=body) + value,_=measure(label,call) if timed else (call(),0) + assert value['changed']==len(keys) + if 'persistence' in value: + assert value['persistence']['database']=='committed',value + report['backup_receipts'].append({'operation':label,'persistence':value['persistence']}) + for key in keys: + revisions[(kind,key,p)]+=1 + if add:model[(kind,key,p)].add(marker) + else:model[(kind,key,p)].remove(marker) + assert set(value['targets'])==set(keys) + for key,row in value['targets'].items():validate_target(row,kind,key) + # The oracle uses the application's actual SQL lock so the + # candidate's background mirror cannot race this connection. + with app_db_lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':kind,'profile_uuid':authors[p]}&[{'target_uuid':key} for key in keys]).to_dicts() + assert {row['target_uuid'] for row in rows}==set(keys) + for row in rows: + key=row['target_uuid'];assert row['revision']==revisions[(kind,key,p)] and sorted(row['tags'])==wanted_tags(kind,key,p) + return value + def query(predicate,**extra):return {'tag_predicate':json.dumps(predicate,separators=(',',':')),**extra} + def page(label,predicate,wanted,*,offset=0,timed=True): + call=lambda:request('GET',base+'/epochs',query=query(predicate,limit=60,offset=offset,include_cells='true')) + value,elapsed=measure(label,call) if timed else (call(),0) + assert value['total']==len(wanted) + assert tuple(row['epoch_uuid'] for row in value['epochs'])==wanted[offset:offset+60] + counts={} + for key in wanted: + target_cell=service.rows[key]['cell_uuid'];counts[target_cell]=counts.get(target_cell,0)+1 + assert {row['cell_uuid']:row['epochs'] for row in value['cells']}==counts + for row in value['epochs']: + key=row['epoch_uuid'];target_cell=service.rows[key]['cell_uuid'] + for kind,field,target in [('epoch','epoch_tags',key),('cell','cell_tags',target_cell)]: + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['annotations'][field])==sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,target,p)) + assert row['curation']['revision']==1 + assert sorted(row['curation']['tags'])==sorted(['dataset:0',*[f'dataset-tag:{j}' for j in range(4)]]) + with app_db_lock: + exact,_=service._epoch_page_identities(protocol,query(predicate));assert tuple(exact)==wanted + return value,elapsed + def child_sql(): + with app_db_lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'}&[{'target_uuid':key} for key in children]).to_dicts() + return sorted((row['target_uuid'],row['profile_uuid'],row['revision'],tuple(sorted(row['tags'])),row['author_name'],str(row['updated_at'])) for row in rows) + # Native lookup is persistent. The first filter is requested + # only after the two timed writes, without warming a tag cache. + prepare_project_annotations=None + report['preparation_index_seconds']=0 + report['lookup_mode']='persistent_native_sql_no_post_seed_tag_cache_preparation' + report['bundle_definitions']={ + 'tag10_then10_filter20_http_total':['first10_revision_preflight','first10_save','second10_revision_preflight','second10_save','filter20'], + 'cell_tag_then_cell_filter_http_total':['cell_save','filter_cell100'], + 'first10_selected_action_http_total':['first10_revision_preflight','first10_save'], + 'second10_selected_action_http_total':['second10_revision_preflight','second10_save']} + for iteration in range(args.samples): + p=iteration%3 + expected=preflight('first10_revision_preflight',first,p) + change('first10_save','epoch',first,p,epoch_marker,True,expected) + expected=preflight('second10_revision_preflight',second,p) + change('second10_save','epoch',second,p,epoch_marker,True,expected) + value,_=page('filter20',epoch_predicate,selected) + before_children=child_sql() + # The rendered page already carries cell revisions, as the + # direct-cell editor does; no selected-epoch preflight. + cell_expected={cell:value['epochs'][0]['annotations']['revisions']['cell'][authors[p]]} + change('cell_save','cell',(cell,),p,cell_marker,True,cell_expected) + page('filter_cell100',cell_predicate,children) + page('filter_cell100_last_page',cell_predicate,children,offset=40,timed=False) + page('filter_cell_and_epoch10',hierarchy,first) + page('oracle_cell_marker_not_direct',{'all':[rule(cell_marker,'epoch')]},(),timed=False) + assert child_sql()==before_children,'Cell add changed child annotation records' + expected=preflight('remove_first10_revision_preflight',first,p) + change('remove_first10_save','epoch',first,p,epoch_marker,False,expected) + page('filter_hierarchy_after_epoch_remove',hierarchy,()) + page('filter_remaining10',epoch_predicate,second) + expected=preflight('remove_second10_revision_preflight',second,p) + change('remove_second10_save','epoch',second,p,epoch_marker,False,expected) + page('filter_after_all_epoch_removals',epoch_predicate,()) + before_children=child_sql() + change('remove_cell_save','cell',(cell,),p,cell_marker,False) + page('filter_after_cell_removal',cell_predicate,()) + assert child_sql()==before_children,'Cell removal changed child annotation records' + with app_db_lock:assert len(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'})==args.epochs*3 + for label,parts in report['bundle_definitions'].items():samples.setdefault(label,[]).append(sum(samples[part][-1] for part in parts)) + log(json.dumps({'stage':'sequence_cycle','epochs':args.epochs,'iteration':iteration+1})) + def flush_backup(): + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush();report['final_backup_status']=scheduler.status() + # Separate one-sample diagnostics; neither request warms the + # measured write/filter sequence above. + flush_backup() + autocomplete_explain={};report['autocomplete_sql']={};report['autocomplete_requests']={} + from collections import Counter,defaultdict + expected_counts=Counter();expected_authors=defaultdict(set) + for kind,count in (('epoch',args.epochs),('cell',len(service.cells))): + for ordinal in range(count): + target_tags=set() + for p in range(3): + seeded=tags(ordinal,p,cell=kind=='cell');target_tags.update(seeded) + for tag in seeded:expected_authors[tag].add(p) + expected_counts.update(target_tags) + empty_candidates=sorted(expected_counts,key=lambda tag:(-expected_counts[tag],tag.casefold(),tag)) + for label,search in (('autocomplete_cold_diagnostic','gate'),('autocomplete_warm_diagnostic','gate'),('autocomplete_empty_diagnostic','')): + connection=dj.conn();original_query=connection.query;owner=threading.get_ident();selected_queries=[] + def trace_autocomplete_sql(statement,*positional,**keywords): + began=time.perf_counter();cursor=None + try: + cursor=original_query(statement,*positional,**keywords) + return cursor + finally: + if threading.get_ident()==owner and str(statement).lstrip().upper().startswith('SELECT') and any(table in str(statement) for table in ('`app_shared_tag_lookup`','`app_shared_tag_dictionary`','`app_shared_tag_authors`','`shared_annotation`')): + selected_queries.append({'sql':str(statement),'seconds':time.perf_counter()-began,'result_rows':getattr(cursor,'rowcount',None)}) + autocomplete_explain[str(statement)]=positional[0] if positional else keywords.get('args') + connection.query=trace_autocomplete_sql + try:value,_=measure(label,lambda:request('GET','/api/annotation-tags',query={'q':search,'limit':12})) + finally:connection.query=original_query + report['autocomplete_sql'][label]=selected_queries + report['autocomplete_requests'][label]={'q':search,'limit':12,'total':value['total']} + if search: + expected=[{'tag':f'gate:{p}','count':(args.epochs+p+1)//(p+2), + 'authors':[{'profile_uuid':authors[p],'display_name':author_names[p]}]} for p in range(3)] + expected_total=3 + else: + expected=[{'tag':tag,'count':expected_counts[tag], + 'authors':sorted([{'profile_uuid':authors[p],'display_name':author_names[p]} for p in expected_authors[tag]],key=lambda author:author['profile_uuid'])} + for tag in empty_candidates[:12]] + expected_total=len(empty_candidates) + assert value['tags']==expected and value['total']==expected_total,(label,value,expected) + with app_db_lock: + report['autocomplete_query_plans']=[{'sql':statement,'explain':list(connection.query('EXPLAIN '+statement,parameters,as_dict=True,reconnect=False).fetchall())} + for statement,parameters in autocomplete_explain.items()] + check('native_autocomplete_exact_counts_and_profile_authors',True) + import re + autocomplete_queries=[item for values in report['autocomplete_sql'].values() for item in values] + membership_queries=[item for item in autocomplete_queries if '`app_shared_tag_lookup`' in item['sql']] + check('autocomplete_has_no_membership_aggregation',all( + not re.search(r'\b(?:COUNT|SUM|MAX|MIN|AVG)\s*\(|\bGROUP\s+BY\b|\bDISTINCT\b',item['sql'],re.I) + and re.search(r'\bLIMIT\s+1\b',item['sql'],re.I) + and item['result_rows'] in (0,1) for item in membership_queries), + membership_selects=len(membership_queries),maximum_rows_per_seek=max((item['result_rows'] for item in membership_queries),default=0)) + dictionary_queries=[item for item in autocomplete_queries if '`app_shared_tag_dictionary`' in item['sql']] + check('autocomplete_compact_dictionary_fetches_are_bounded',bool(dictionary_queries) and all( + re.search(r'\bCOUNT\s*\(',item['sql'],re.I) or re.search(r'\bLIMIT\b',item['sql'],re.I) + for item in dictionary_queries),dictionary_selects=len(dictionary_queries), + scope='Counts may scan matching compact entries; no unbounded dictionary rows are fetched for Python prefix filtering.') + membership_plans=[row for item in report['autocomplete_query_plans'] if '`app_shared_tag_lookup`' in item['sql'] for row in item['explain']] + check('autocomplete_membership_winner_seeks_are_indexed',all(row.get('key')=='by_tag' and row.get('type') in {'const','ref','range','eq_ref'} for row in membership_plans),plans=membership_plans) + if args.profile: + for name,keys in [('first10',first),('second10',second)]: + expected=preflight('profile_'+name+'_preflight',keys,0,timed=False) + change('profile_'+name+'_save','epoch',keys,0,epoch_marker,True,expected,timed=False) + flush_backup() + import re + connection=dj.conn();original_query=connection.query;owner=threading.get_ident();sql_calls=[];lookup_selects=[] + def traced_query(statement,*positional,**keywords): + began=time.perf_counter() + try:return original_query(statement,*positional,**keywords) + finally: + is_filter=threading.get_ident()==owner + sql_calls.append({'thread':'filter' if is_filter else 'background','sql_shape':re.sub(r"'[^']*'","'?'",str(statement))[:240],'seconds':time.perf_counter()-began}) + if is_filter and str(statement).lstrip().upper().startswith('SELECT') and '`app_shared_tag_lookup`' in str(statement): + lookup_selects.append((str(statement),positional[0] if positional else keywords.get('args'))) + profiler=cProfile.Profile();connection.query=traced_query + try:profiled=profiler.runcall(lambda:request('GET',base+'/epochs',query=query(epoch_predicate,limit=60,offset=0,include_cells='true'))) + finally:connection.query=original_query + assert profiled['total']==20 and tuple(row['epoch_uuid'] for row in profiled['epochs'])==selected + stats=pstats.Stats(profiler);rows=[] + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True): + path=Path(key[0]);rows.append({'file':str(path.relative_to(root)) if path.is_absolute() and path.is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'primitive_calls':value[0],'calls':value[1],'self_seconds':value[2],'cumulative_seconds':value[3]}) + report['filter20_cpu_profile']={'top_functions':rows[:100],'native_sql_calls':sql_calls,'limits':'Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap.'} + assert lookup_selects,'The fresh filter did not execute a native tag lookup SELECT' + plans=[] + with app_db_lock: + for statement,parameters in lookup_selects: + explanation=list(connection.query('EXPLAIN '+statement,parameters,as_dict=True,reconnect=False).fetchall()) + assert any(row.get('key')=='by_tag' and row.get('type') in ('ref','range','const','eq_ref') for row in explanation),explanation + plans.append({'sql':statement,'explain':explanation}) + report['native_lookup_query_plans']=plans + check('actual_filter_uses_persistent_by_tag_sql_index',True,queries=len(plans)) + page('profile_filter20_verify',epoch_predicate,selected,timed=False) + from workspace_annotation_preparation import prepare_project_annotations as prepare_native_lookup + flush_backup();began=time.perf_counter() + with app_db_lock: + checkpoint=prepare_native_lookup(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader')) + assert checkpoint['status']=='ready' and checkpoint['storage']=='native_sql',checkpoint + shared.native_tag_lookup=None + reopened=prepare_native_lookup(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader'),reuse=True) + assert reopened['status']=='ready' and reopened['storage']=='native_sql' and reopened['reused'],reopened + report['same_server_native_lookup_reuse']={'checkpoint':checkpoint,'reopened':reopened,'seconds':time.perf_counter()-began, + 'scope':'Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart.'} + page('same_server_native_reuse_filter20',epoch_predicate,selected) + check('persistent_native_lookup_reused_without_rebuild',True) + if prepare_project_annotations is not None: + flush_backup();began=time.perf_counter() + with app_db_lock: + checkpoint=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader')) + assert checkpoint['status']=='ready' and checkpoint['checkpoint']['saved'],checkpoint + previous_builds=shared._shared_tag_index.stats['full_builds'] + shared._shared_tag_index.close() + reopened=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader'),reuse=True) + assert reopened['status']=='ready' and reopened['checkpoint_restore']['restored'],reopened + after_builds=shared._shared_tag_index.stats['full_builds'] + assert after_builds in (0,previous_builds),(previous_builds,after_builds) + report['same_server_checkpoint_reopen']={'seconds':time.perf_counter()-began,'checkpoint':checkpoint,'reopened':reopened,'full_builds_before':previous_builds,'full_builds_after':after_builds,'scope':'Shared derived index closed and reopened within the same native server; not a native process restart.'} + page('same_server_reopened_filter20',epoch_predicate,selected) + check('same_server_checkpoint_restores_exact_twenty_without_rebuild',True) + for name,keys in [('first10',first),('second10',second)]: + change('profile_remove_'+name,'epoch',keys,0,epoch_marker,False,timed=False) + # Untimed exactness checks run after the measured workflow. + unicode_oracles=[ + ('case_upper',{'all':[rule('QC','epoch')]},lambda i:i%2==0), + ('case_lower',{'all':[rule('qc','epoch')]},lambda i:i%2==1), + ('unicode_nfc',{'all':[rule('é','epoch')]},lambda i:i%3==0), + ('unicode_nfd',{'all':[rule('e\u0301','epoch')]},lambda i:i%3!=0), + ('or',{'any':[rule('QC','epoch'),rule('é','epoch')]},lambda i:i%2==0 or i%3==0), + ('not_with_inheritance',{'all':[rule('cell-common','cell'),{'not':rule('QC','epoch')}]},lambda i:i%2==1), + ('inherited_excluded_from_direct',{'all':[rule('cell-common','epoch')]},lambda i:False)] + for label,predicate,accept in unicode_oracles: + wanted=tuple(identity for i,identity in enumerate(ids) if accept(i)) + page('oracle_'+label,predicate,wanted,timed=False) + check('exact_native_'+label,True,count=len(wanted)) + report['sqlite_tag_cache_calls']=dict(sqlite_tag_calls) + check('no_sqlite_tag_membership_or_refresh_used',not any(sqlite_tag_calls.values()),calls=sqlite_tag_calls) + flush_backup() + check('canonical_final_markers_removed',not any(model.values())) + report['workflow_peak_rss_before_durable_oracle_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + began=time.perf_counter();state=snapshot.load(project_root/'app-state.json');report['durable_snapshot_verify_seconds']=time.perf_counter()-began + saved={(row['target_kind'],row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation']} + for (kind,key,p),revision in revisions.items(): + row=saved[(kind,key,authors[p])];assert row['revision']==revision and sorted(row['tags'])==wanted_tags(kind,key,p) + check('flushed_recovery_mirror_exact_revisions_and_removal',True,records=len(revisions)) + check('one_canonical_cell_record_no_child_copies',sum(row['target_kind']=='epoch' for row in saved.values())==args.epochs*3,child_epochs=len(children)) + check('independent_protocol_curation_untouched',len(state['tables']['curation'])==args.epochs*2 and all(row['revision']==1 for row in state['tables']['curation'])) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_loaded_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values()));report['loaded_product_modules']=loaded + finally: + if app is not None: + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush() + close=getattr(scheduler,'close',None) + if close is not None:close(flush=False) + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['harness_unchanged']=digest(__file__)==report['harness_sha256'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and report['harness_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence_post_profile.py b/docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence_post_profile.py new file mode 100644 index 0000000..949db4c --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence_post_profile.py @@ -0,0 +1,413 @@ +"""Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and each version's save hooks +are used. Native SQL commits are checked immediately; any background recovery +mirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=5);ap.add_argument('--targets',default='tag10_then10_filter20_and_cell_epoch_hierarchy') + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true') + ap.add_argument('--page-cells',action='store_true',default=True) + args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<200 or args.samples<1:ap.error('Use at least200 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + import importlib.util + from workspace_annotations import SharedAnnotations + sqlite_tag_calls={'membership_index':0,'refresh':0} + original_membership=getattr(SharedAnnotations,'_membership_index',None) + if original_membership is not None: + def observed_membership(*args,**kwargs): + sqlite_tag_calls['membership_index']+=1 + return original_membership(*args,**kwargs) + SharedAnnotations._membership_index=observed_membership + if importlib.util.find_spec('workspace_shared_tag_index') is not None: + from workspace_shared_tag_index import SharedTagIndex + original_refresh=SharedTagIndex.refresh + def observed_refresh(*args,**kwargs): + sqlite_tag_calls['refresh']+=1 + return original_refresh(*args,**kwargs) + SharedTagIndex.refresh=observed_refresh + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[], + 'page_cells':True,'target_specification':args.targets,'baseline_harness_sha256':digest(Path(__file__).with_name('benchmark_scientist_tag_workflow.py'))} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-native-tag-sequence-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + service.manifests={item['source_sha256']:{'source_path':'/synthetic/'+item['filename']} for item in service.sources} + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'];authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:shared.Annotation.insert(batch);batch=[] + if batch:shared.Annotation.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:store.Curation.insert(batch);batch=[] + if batch:store.Curation.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + + + import inspect + import threading + app_db_lock=inspect.getclosurevars(app.view_functions['annotation_batch_read']).nonlocals['db_lock'] + report['native_lookup_startup_preparation']=copy.deepcopy(getattr(service,'annotation_preparation',None)) + first=ids[:10];second=ids[100:110];selected=first+second;cell=service.rows[first[0]]['cell_uuid'] + children=tuple(key for key in ids if service.rows[key]['cell_uuid']==cell) + assert len(children)==100 and service.rows[second[0]]['cell_uuid']!=cell + epoch_marker='sequence-selected';cell_marker='sequence-cell' + epoch_predicate={'all':[rule(epoch_marker,'epoch')]} + cell_predicate={'all':[rule(cell_marker,'cell')]} + hierarchy={'all':[rule(cell_marker,'cell'),rule(epoch_marker,'epoch')]} + model={(kind,key,p):set() for kind,keys in [('epoch',selected),('cell',(cell,))] for key in keys for p in range(3)} + revisions={key:1 for key in model} + report['selected_epoch_uuids']={'first10':first,'second10':second,'cell':cell,'cell_children':children} + report['backup_receipts']=[] + def sql_status(): + with app_db_lock:return {key:int(value) for key,value in dj.conn().query("SHOW SESSION STATUS WHERE Variable_name IN ('Bytes_sent','Questions')").fetchall()} + def request(method,path,*,query=None,body=None): + response=client.get(path,query_string=query) if method=='GET' else client.post(path,json=body,headers=headers) + value=response.get_json() + if response.status_code!=200:raise AssertionError((method,path,response.status_code,value)) + return value + def measure(name,callback): + before=sql_status();began=time.perf_counter();value=callback();elapsed=time.perf_counter()-began;after=sql_status() + samples.setdefault(name,[]).append(elapsed);sql_samples.setdefault(name,[]).append({key:after[key]-before[key] for key in before}) + return value,elapsed + def wanted_tags(kind,key,p): + ordinal=ordinals[key] if kind=='epoch' else cell_ordinals[key] + return sorted([*tags(ordinal,p,cell=kind=='cell'),*model.get((kind,key,p),())]) + def validate_target(row,kind,key): + assert row['target_uuid']==key and row['target_kind']==kind + assert row['revisions']=={author:revisions.get((kind,key,p),1) for p,author in enumerate(authors)} + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['tags'])==sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,key,p)) + def preflight(label,keys,p,*,timed=True): + call=lambda:request('POST','/api/annotations/read',body={'target_kind':'epoch','target_uuids':list(keys)}) + value,_=measure(label,call) if timed else (call(),0) + assert set(value['targets'])==set(keys) + for key,row in value['targets'].items():validate_target(row,'epoch',key) + return {key:value['targets'][key]['revisions'][authors[p]] for key in keys} + def change(label,kind,keys,p,marker,add,expected=None,*,timed=True): + body={'target_kind':kind,'target_uuids':list(keys),'profile_uuid':authors[p], + 'tags_add':[marker] if add else [],'tags_remove':[] if add else [marker], + 'expected_revisions':expected or {key:revisions[(kind,key,p)] for key in keys}} + call=lambda:request('POST','/api/annotations',body=body) + if label=='profile_first10_save': + import re + connection=dj.conn();original_query=connection.query;sql_details=[];profile_owner=threading.get_ident() + def trace_post_sql(statement,*positional,**keywords): + began=time.perf_counter() + try:return original_query(statement,*positional,**keywords) + finally: + if threading.get_ident()==profile_owner:sql_details.append({'sql_shape':re.sub(r"'[^']*'","'?'",str(statement))[:400],'seconds':time.perf_counter()-began}) + profiler=cProfile.Profile();connection.query=trace_post_sql + try:value=profiler.runcall(call) + finally:connection.query=original_query + statistics_profile=pstats.Stats(profiler) + functions=[] + for key,entry in sorted(statistics_profile.stats.items(),key=lambda item:item[1][3],reverse=True): + path=Path(key[0]);functions.append({'file':str(path.relative_to(root)) if path.is_absolute() and path.is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'calls':entry[1],'self_seconds':entry[2],'cumulative_seconds':entry[3]}) + report['actual_post10_profile']={'functions':functions[:160],'sql':sql_details} + else:value,_=measure(label,call) if timed else (call(),0) + assert value['changed']==len(keys) + if 'persistence' in value: + assert value['persistence']['database']=='committed',value + report['backup_receipts'].append({'operation':label,'persistence':value['persistence']}) + for key in keys: + revisions[(kind,key,p)]+=1 + if add:model[(kind,key,p)].add(marker) + else:model[(kind,key,p)].remove(marker) + assert set(value['targets'])==set(keys) + for key,row in value['targets'].items():validate_target(row,kind,key) + # The oracle uses the application's actual SQL lock so the + # candidate's background mirror cannot race this connection. + with app_db_lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':kind,'profile_uuid':authors[p]}&[{'target_uuid':key} for key in keys]).to_dicts() + assert {row['target_uuid'] for row in rows}==set(keys) + for row in rows: + key=row['target_uuid'];assert row['revision']==revisions[(kind,key,p)] and sorted(row['tags'])==wanted_tags(kind,key,p) + return value + def query(predicate,**extra):return {'tag_predicate':json.dumps(predicate,separators=(',',':')),**extra} + def page(label,predicate,wanted,*,offset=0,timed=True): + call=lambda:request('GET',base+'/epochs',query=query(predicate,limit=60,offset=offset,include_cells='true')) + value,elapsed=measure(label,call) if timed else (call(),0) + assert value['total']==len(wanted) + assert tuple(row['epoch_uuid'] for row in value['epochs'])==wanted[offset:offset+60] + counts={} + for key in wanted: + target_cell=service.rows[key]['cell_uuid'];counts[target_cell]=counts.get(target_cell,0)+1 + assert {row['cell_uuid']:row['epochs'] for row in value['cells']}==counts + for row in value['epochs']: + key=row['epoch_uuid'];target_cell=service.rows[key]['cell_uuid'] + for kind,field,target in [('epoch','epoch_tags',key),('cell','cell_tags',target_cell)]: + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['annotations'][field])==sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,target,p)) + assert row['curation']['revision']==1 + assert sorted(row['curation']['tags'])==sorted(['dataset:0',*[f'dataset-tag:{j}' for j in range(4)]]) + with app_db_lock: + exact,_=service._epoch_page_identities(protocol,query(predicate));assert tuple(exact)==wanted + return value,elapsed + def child_sql(): + with app_db_lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'}&[{'target_uuid':key} for key in children]).to_dicts() + return sorted((row['target_uuid'],row['profile_uuid'],row['revision'],tuple(sorted(row['tags'])),row['author_name'],str(row['updated_at'])) for row in rows) + # Native lookup is persistent. The first filter is requested + # only after the two timed writes, without warming a tag cache. + prepare_project_annotations=None + report['preparation_index_seconds']=0 + report['lookup_mode']='persistent_native_sql_no_post_seed_tag_cache_preparation' + report['bundle_definitions']={ + 'tag10_then10_filter20_http_total':['first10_revision_preflight','first10_save','second10_revision_preflight','second10_save','filter20'], + 'cell_tag_then_cell_filter_http_total':['cell_save','filter_cell100'], + 'first10_selected_action_http_total':['first10_revision_preflight','first10_save'], + 'second10_selected_action_http_total':['second10_revision_preflight','second10_save']} + for iteration in range(args.samples): + p=iteration%3 + expected=preflight('first10_revision_preflight',first,p) + change('first10_save','epoch',first,p,epoch_marker,True,expected) + expected=preflight('second10_revision_preflight',second,p) + change('second10_save','epoch',second,p,epoch_marker,True,expected) + value,_=page('filter20',epoch_predicate,selected) + before_children=child_sql() + # The rendered page already carries cell revisions, as the + # direct-cell editor does; no selected-epoch preflight. + cell_expected={cell:value['epochs'][0]['annotations']['revisions']['cell'][authors[p]]} + change('cell_save','cell',(cell,),p,cell_marker,True,cell_expected) + page('filter_cell100',cell_predicate,children) + page('filter_cell100_last_page',cell_predicate,children,offset=40,timed=False) + page('filter_cell_and_epoch10',hierarchy,first) + page('oracle_cell_marker_not_direct',{'all':[rule(cell_marker,'epoch')]},(),timed=False) + assert child_sql()==before_children,'Cell add changed child annotation records' + expected=preflight('remove_first10_revision_preflight',first,p) + change('remove_first10_save','epoch',first,p,epoch_marker,False,expected) + page('filter_hierarchy_after_epoch_remove',hierarchy,()) + page('filter_remaining10',epoch_predicate,second) + expected=preflight('remove_second10_revision_preflight',second,p) + change('remove_second10_save','epoch',second,p,epoch_marker,False,expected) + page('filter_after_all_epoch_removals',epoch_predicate,()) + before_children=child_sql() + change('remove_cell_save','cell',(cell,),p,cell_marker,False) + page('filter_after_cell_removal',cell_predicate,()) + assert child_sql()==before_children,'Cell removal changed child annotation records' + with app_db_lock:assert len(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'})==args.epochs*3 + for label,parts in report['bundle_definitions'].items():samples.setdefault(label,[]).append(sum(samples[part][-1] for part in parts)) + log(json.dumps({'stage':'sequence_cycle','epochs':args.epochs,'iteration':iteration+1})) + def flush_backup(): + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush();report['final_backup_status']=scheduler.status() + # Separate one-sample diagnostics; neither request warms the + # measured write/filter sequence above. + flush_backup() + for label in ('autocomplete_cold_diagnostic','autocomplete_warm_diagnostic'): + value,_=measure(label,lambda:request('GET','/api/annotation-tags',query={'q':'gate','limit':12})) + expected=[{'tag':f'gate:{p}','count':(args.epochs+p+1)//(p+2), + 'authors':[{'profile_uuid':authors[p],'display_name':author_names[p]}]} for p in range(3)] + assert value['tags']==expected and value['total']==3,(label,value,expected) + check('native_autocomplete_exact_counts_and_profile_authors',True) + if args.profile: + for name,keys in [('first10',first),('second10',second)]: + expected=preflight('profile_'+name+'_preflight',keys,0,timed=False) + change('profile_'+name+'_save','epoch',keys,0,epoch_marker,True,expected,timed=False) + flush_backup() + import re + connection=dj.conn();original_query=connection.query;owner=threading.get_ident();sql_calls=[];lookup_selects=[] + def traced_query(statement,*positional,**keywords): + began=time.perf_counter() + try:return original_query(statement,*positional,**keywords) + finally: + is_filter=threading.get_ident()==owner + sql_calls.append({'thread':'filter' if is_filter else 'background','sql_shape':re.sub(r"'[^']*'","'?'",str(statement))[:240],'seconds':time.perf_counter()-began}) + if is_filter and str(statement).lstrip().upper().startswith('SELECT') and '`app_shared_tag_lookup`' in str(statement): + lookup_selects.append((str(statement),positional[0] if positional else keywords.get('args'))) + profiler=cProfile.Profile();connection.query=traced_query + try:profiled=profiler.runcall(lambda:request('GET',base+'/epochs',query=query(epoch_predicate,limit=60,offset=0,include_cells='true'))) + finally:connection.query=original_query + assert profiled['total']==20 and tuple(row['epoch_uuid'] for row in profiled['epochs'])==selected + stats=pstats.Stats(profiler);rows=[] + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True): + path=Path(key[0]);rows.append({'file':str(path.relative_to(root)) if path.is_absolute() and path.is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'primitive_calls':value[0],'calls':value[1],'self_seconds':value[2],'cumulative_seconds':value[3]}) + report['filter20_cpu_profile']={'top_functions':rows[:100],'native_sql_calls':sql_calls,'limits':'Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap.'} + assert lookup_selects,'The fresh filter did not execute a native tag lookup SELECT' + plans=[] + with app_db_lock: + for statement,parameters in lookup_selects: + explanation=list(connection.query('EXPLAIN '+statement,parameters,as_dict=True,reconnect=False).fetchall()) + assert any(row.get('key')=='by_tag' and row.get('type') in ('ref','range','const','eq_ref') for row in explanation),explanation + plans.append({'sql':statement,'explain':explanation}) + report['native_lookup_query_plans']=plans + check('actual_filter_uses_persistent_by_tag_sql_index',True,queries=len(plans)) + page('profile_filter20_verify',epoch_predicate,selected,timed=False) + from workspace_annotation_preparation import prepare_project_annotations as prepare_native_lookup + flush_backup();began=time.perf_counter() + with app_db_lock: + checkpoint=prepare_native_lookup(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader')) + assert checkpoint['status']=='ready' and checkpoint['storage']=='native_sql',checkpoint + shared.native_tag_lookup=None + reopened=prepare_native_lookup(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader'),reuse=True) + assert reopened['status']=='ready' and reopened['storage']=='native_sql' and reopened['reused'],reopened + report['same_server_native_lookup_reuse']={'checkpoint':checkpoint,'reopened':reopened,'seconds':time.perf_counter()-began, + 'scope':'Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart.'} + page('same_server_native_reuse_filter20',epoch_predicate,selected) + check('persistent_native_lookup_reused_without_rebuild',True) + if prepare_project_annotations is not None: + flush_backup();began=time.perf_counter() + with app_db_lock: + checkpoint=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader')) + assert checkpoint['status']=='ready' and checkpoint['checkpoint']['saved'],checkpoint + previous_builds=shared._shared_tag_index.stats['full_builds'] + shared._shared_tag_index.close() + reopened=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader'),reuse=True) + assert reopened['status']=='ready' and reopened['checkpoint_restore']['restored'],reopened + after_builds=shared._shared_tag_index.stats['full_builds'] + assert after_builds in (0,previous_builds),(previous_builds,after_builds) + report['same_server_checkpoint_reopen']={'seconds':time.perf_counter()-began,'checkpoint':checkpoint,'reopened':reopened,'full_builds_before':previous_builds,'full_builds_after':after_builds,'scope':'Shared derived index closed and reopened within the same native server; not a native process restart.'} + page('same_server_reopened_filter20',epoch_predicate,selected) + check('same_server_checkpoint_restores_exact_twenty_without_rebuild',True) + for name,keys in [('first10',first),('second10',second)]: + change('profile_remove_'+name,'epoch',keys,0,epoch_marker,False,timed=False) + # Untimed exactness checks run after the measured workflow. + unicode_oracles=[ + ('case_upper',{'all':[rule('QC','epoch')]},lambda i:i%2==0), + ('case_lower',{'all':[rule('qc','epoch')]},lambda i:i%2==1), + ('unicode_nfc',{'all':[rule('é','epoch')]},lambda i:i%3==0), + ('unicode_nfd',{'all':[rule('e\u0301','epoch')]},lambda i:i%3!=0), + ('or',{'any':[rule('QC','epoch'),rule('é','epoch')]},lambda i:i%2==0 or i%3==0), + ('not_with_inheritance',{'all':[rule('cell-common','cell'),{'not':rule('QC','epoch')}]},lambda i:i%2==1), + ('inherited_excluded_from_direct',{'all':[rule('cell-common','epoch')]},lambda i:False)] + for label,predicate,accept in unicode_oracles: + wanted=tuple(identity for i,identity in enumerate(ids) if accept(i)) + page('oracle_'+label,predicate,wanted,timed=False) + check('exact_native_'+label,True,count=len(wanted)) + report['sqlite_tag_cache_calls']=dict(sqlite_tag_calls) + check('no_sqlite_tag_membership_or_refresh_used',not any(sqlite_tag_calls.values()),calls=sqlite_tag_calls) + flush_backup() + check('canonical_final_markers_removed',not any(model.values())) + report['workflow_peak_rss_before_durable_oracle_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + began=time.perf_counter();state=snapshot.load(project_root/'app-state.json');report['durable_snapshot_verify_seconds']=time.perf_counter()-began + saved={(row['target_kind'],row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation']} + for (kind,key,p),revision in revisions.items(): + row=saved[(kind,key,authors[p])];assert row['revision']==revision and sorted(row['tags'])==wanted_tags(kind,key,p) + check('flushed_recovery_mirror_exact_revisions_and_removal',True,records=len(revisions)) + check('one_canonical_cell_record_no_child_copies',sum(row['target_kind']=='epoch' for row in saved.values())==args.epochs*3,child_epochs=len(children)) + check('independent_protocol_curation_untouched',len(state['tables']['curation'])==args.epochs*2 and all(row['revision']==1 for row in state['tables']['curation'])) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_loaded_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values()));report['loaded_product_modules']=loaded + finally: + if app is not None: + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush() + close=getattr(scheduler,'close',None) + if close is not None:close(flush=False) + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['harness_unchanged']=digest(__file__)==report['harness_sha256'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and report['harness_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_protocol_state.py b/docs/dev/scale-audit-2026-09-29/benchmark_protocol_state.py new file mode 100644 index 0000000..c01183b --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_protocol_state.py @@ -0,0 +1,130 @@ +"""Actual Flask100k page before/after exact revision reuse, disposable SQL doubles.""" +import argparse +import copy +import json +import sys +from pathlib import Path +import tempfile +from unittest.mock import patch + +from benchmark_service_scale import fixture,Details +from benchmark_epoch_pages import measure +from workspace_disk_index import DiskMetadataIndex +from workspace_service import WorkspaceService +from workspace_protocol_state import _exact_equal +from test_workspace_api import WorkspaceAPITests + + +def run(count): + api=WorkspaceAPITests();api.setUp() + try: + service,protocol=fixture(count) + service.project['project_uuid']=api.service.project['project_uuid'] + with tempfile.TemporaryDirectory(prefix='rieke-state-benchmark-') as folder: + index=DiskMetadataIndex.build(Path(folder)/'index.sqlite',service.rows,Details(service.rows), + service.sources,'state-benchmark',service.project['project_uuid']) + target=api.service + target.__class__=WorkspaceService + for name in ('rows','cells','sources','_fingerprints'): + setattr(target,name,getattr(service,name)) + target.disk_index,target.details=index,index.details + target.protocols={target.protocol_id:service.protocols[protocol]} + target.protocols[target.protocol_id]['result']['protocol_uuid']=target.protocol_id + reader=api.app.extensions['protocol_state_reader'] + path=api.base+'/epochs?limit=60' + target.epoch_page(target.protocol_id,limit=60) # Both HTTP cases use the optimized page service. + def request(): + response=api.client.get(path) + assert response.status_code==200,response.get_json() + return response.get_json() + def uncached(protocol,ids): + result,states,revision=reader.full_state(protocol) + return {key:states[key] for key in ids},revision,result.get('dataset_binding',{}).get('version',0) + with patch.object(reader,'read_selected',side_effect=uncached): + baseline,old=measure(request) + cold,new=measure(request,1) + assert old==new,'Cold cached path must preserve the exact legacy JSON response' + assert target.protocol_id in reader.cache,'100k scope must fit the admission budget' + with patch.object(reader,'full_state',side_effect=AssertionError('No full-state hydration on warm read')): + warm,again=measure(request) + calls=[] + def profile(frame,event,arg): + if event=='call' and frame.f_code is api.store._state.__code__:calls.append(1) + sys.setprofile(profile) + try:structural=request() + finally:sys.setprofile(None) + assert len(calls)==60,len(calls) + assert again==old==structural + first=next(iter(target.rows)) + api.store.update(target.protocol_id,[first],{'tags_add':['after-save']},{first:0}, + {first:target._fingerprints[first]},'fixture') + changed=request() + _,current,revision=reader.full_state(target.protocol_id) + assert changed['query_revision']==revision!=old['query_revision'] + assert changed['epochs'][0]['curation']['tags']==['after-save'] + sparse,_=measure(request) + # Same-version direct SQL edits cannot hide behind a revision counter. + api.curation.rows[0]['tags']=['same-version-change'] + edited=request() + assert edited['query_revision']==reader.full_state(target.protocol_id)[2]!=revision + previous=edited['query_revision'] + target._fingerprints[first]='c'*64 + metadata=request() + assert metadata['query_revision']==reader.full_state(target.protocol_id)[2]!=previous + previous=metadata['query_revision'] + api.curation.rows.clear() + deleted=request() + assert deleted['query_revision']==reader.full_state(target.protocol_id)[2]!=previous + proof=reader._metadata(target.protocol_id) + retained=reader.cache[target.protocol_id]['metadata'] + deepcopy_cost,_=measure(lambda:copy.deepcopy(proof)) + comparison_cost,equal=measure(lambda:reader._metadata_equal(proof,retained)) + assert equal + query_comparison_cost,equal=measure(lambda:_exact_equal(proof['query'],retained['query'])) + assert equal + fingerprint_cost,equal=measure(lambda:proof['fingerprints']==retained['fingerprints']) + assert equal + # Independently exercise a pinned100k dataset: header-only polls + # must preserve the immutable recipe and exact legacy revision. + preview=target.explore_preview({'all':[]},'cell',include_tree=False,include_catalog_summary=False) + saved=api.explorer_history.create(preview,target.sources,'catalog.json','fixture') + api.explorer_history.bind(saved['revision_uuid'],target.protocol_id,0,'fixture',{},count) + target.epoch_page(target.protocol_id,limit=60) + reader.cache.clear() + with patch.object(reader,'read_selected',side_effect=uncached): + bound_baseline,bound_old=measure(request) + bound_cold,bound_new=measure(request,1) + assert bound_old==bound_new + assert target.protocol_id in reader.cache + with patch.object(reader,'full_state',side_effect=AssertionError('Bound warm read must not hydrate recipe')): + bound_warm,bound_new=measure(request) + assert bound_old==bound_new + bound_proof=reader._metadata(target.protocol_id) + bound_cell_cost,_=measure(lambda:reader._bound_cells(reader.cache[target.protocol_id]['members'],bound_proof)) + return {'epochs':count,'response_epochs':60, + 'scope':'Actual production Flask GET route and JSON serialization with a real sealed SQLite metadata index. SQL catalog is a disposable transactional double; initial saved-curation/shared-tag rows are empty, then one saved curation row is added. Excludes real MySQL/network latency, dense tags, browser paint and physical waveform I/O.', + 'legacy_full_revision_http':baseline,'verified_cache_cold_http':cold, + 'verified_cache_warm_http':warm,'verified_cache_one_saved_row_warm_http':sparse, + 'cold_proof_deepcopy':deepcopy_cost,'warm_metadata_equality':comparison_cost, + 'warm_typed_query_comparison':query_comparison_cost,'warm_fingerprint_dictionary_equality':fingerprint_cost, + 'bound_protocol':{'legacy_full_revision_http':bound_baseline,'verified_cache_cold_http':bound_cold, + 'verified_cache_warm_http':bound_warm,'warm_cell_ownership_check':bound_cell_cost, + 'exact_legacy_response_parity':True}, + 'warm_hydrated_curation_states':len(calls), + 'exact_legacy_response_parity':True,'mutation_checks':{ + 'saved_curation_write':True,'same_version_sql_tag_edit':True,'in_place_metadata_fingerprint_change':True, + 'saved_curation_deletion':True,'pinned_binding':True}, + 'cache_scopes':len(reader.cache),'estimated_revision_cache_bytes':sum(item['size'] for item in reader.cache.values()), + 'remaining_linear_checks':'Full fingerprint dictionary equality and typed protocol-metadata comparison occur on each hit. Bound protocols additionally check current cell ownership. Current sparse saved curation and exact shared-annotation snapshot are read every request.'} + finally: + api.doCleanups() + + +if __name__=='__main__': + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs',type=int,default=100000) + parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args() + report=run(args.epochs) + args.output.write_text(json.dumps(report,indent=2)+'\n') + print(json.dumps(report,indent=2),flush=True) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow.py b/docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow.py new file mode 100644 index 0000000..fef555e --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow.py @@ -0,0 +1,255 @@ +"""Native scientist tag/filter workflow against an explicitly selected source tree. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and synchronous durable save hooks +are used. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=20);ap.add_argument('--edit-count',type=int,default=10) + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true');args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<12 or args.samples<1:ap.error('Use at least12 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[]} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-scientist-tag-workflow-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'];authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:shared.Annotation.insert(batch);batch=[] + if batch:shared.Annotation.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:store.Curation.insert(batch);batch=[] + if batch:store.Curation.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + predicates={ + 'A':{'all':[rule('gate:0','epoch'),rule('gate:1','epoch'),rule('cell-common','cell'),{'not':rule('gate:2')}]}, + 'B':{'any':[rule('qc','epoch'),rule('cell-bucket:3','cell'),rule('é','epoch')]}, + 'C':{'all':[{'not':rule('QC')},rule('e\u0301','epoch'),rule('cell-common','cell')]}, + 'direct_inheritance_excluded':{'all':[rule('cell-common','epoch')]}} + expected={ + 'A':tuple(ids[i] for i in range(args.epochs) if i%2==0 and i%3==0 and i%4!=0), + 'B':tuple(ids[i] for i in range(args.epochs) if i%2==1 or (i//100)%5==3 or i%3==0), + 'C':tuple(ids[i] for i in range(args.epochs) if i%2==1 and i%3!=0), + 'direct_inheritance_excluded':()} + edited=expected['A'][:args.edit_count];marker='workflow-selected';dataset_marker='workflow-dataset' + predicates['edited']={'all':[rule(marker,'epoch'),*predicates['A']['all']]};expected['edited']=() + report['filter_contract']={name:{'predicate':predicate,'expected_count':len(expected[name]),'membership_sha256':hashlib.sha256(''.join(expected[name]).encode()).hexdigest()} for name,predicate in predicates.items()} + report['edited_epoch_uuids']=edited;shared_revisions={(key,p):1 for key in edited for p in range(3)};curation_revisions={key:1 for key in edited} + shared_active=None;curation_active=False + def sql_status():return {key:int(value) for key,value in dj.conn().query("SHOW SESSION STATUS WHERE Variable_name IN ('Rows_sent','Bytes_sent','Questions')").fetchall()} + def request(method,path,*,query=None,body=None): + response=client.get(path,query_string=query) if method=='GET' else client.post(path,json=body,headers=headers) + value=response.get_json() + if response.status_code!=200:raise AssertionError((method,path,response.status_code,value)) + return value + def measure(name,callback): + before=sql_status();began=time.perf_counter();value=callback();elapsed=time.perf_counter()-began;after=sql_status() + samples.setdefault(name,[]).append(elapsed);sql_samples.setdefault(name,[]).append({key:after[key]-before[key] for key in before}) + return value,elapsed + def query(name,**extra):return {'tag_predicate':json.dumps(predicates[name],ensure_ascii=False,separators=(',',':')),**extra} + def validate_page(value,name,offset=0): + wanted=expected[name];shown=wanted[offset:offset+60] + assert value['total']==len(wanted) and tuple(row['epoch_uuid'] for row in value['epochs'])==shown,(name,value['total'],len(wanted)) + for row in value['epochs']: + identity=row['epoch_uuid'];i=ordinals[identity];wanted_chips=[] + for p,author in enumerate(authors): + values=tags(i,p)+([marker] if shared_active==p and identity in edited else []) + wanted_chips.extend((tag,author) for tag in values) + actual=sorted((item['tag'],item['profile_uuid']) for item in row['annotations']['epoch_tags']) + assert actual==sorted(wanted_chips),(name,identity,'author tag chips') + cell_i=cell_ordinals[service.rows[identity]['cell_uuid']] + wanted_inherited=sorted((tag,author) for p,author in enumerate(authors) for tag in tags(cell_i,p,cell=True)) + assert sorted((item['tag'],item['profile_uuid']) for item in row['annotations']['cell_tags'])==wanted_inherited + assert row['curation']['revision']==curation_revisions.get(identity,1) + assert sorted(row['curation']['tags'])==sorted(['dataset:0',*[f'dataset-tag:{j}' for j in range(4)]]+([dataset_marker] if curation_active and identity in edited else [])) + def page(label,name,offset=0): + value,elapsed=measure(label,lambda:request('GET',base+'/epochs',query=query(name,limit=60,offset=offset))) + validate_page(value,name,offset);return value,elapsed + def summary(label,name): + value,elapsed=measure(label,lambda:request('GET',base,query=query(name))) + assert value['counts']['epochs']==len(expected[name]),(name,value['counts'],len(expected[name]));return value,elapsed + def bundle(label,name): + _,a=summary(label+'_summary',name);value,b=page(label+'_page',name);samples.setdefault(label+'_server_bundle',[]).append(a+b);return value + def suggest(label,prefix): + value,elapsed=measure(label,lambda:request('GET','/api/annotation-tags',query={'q':prefix,'limit':12})) + if prefix=='gate': + wanted=[{'tag':f'gate:{p}','count':(args.epochs+p+1)//(p+2),'authors':[{'profile_uuid':authors[p],'display_name':author_names[p]}]} for p in range(3)] + else:wanted=[] if shared_active is None else [{'tag':marker,'count':len(edited),'authors':[{'profile_uuid':authors[shared_active],'display_name':author_names[shared_active]}]}] + assert value['tags']==wanted and value['total']==len(wanted),(prefix,value,wanted) + return value + for name in predicates: + if name=='edited':continue + page('cold_filter_'+name,name) + last=max(0,len(expected[name])-60);page('oracle_boundary_'+name,name,last) + exact,_=service._epoch_page_identities(protocol,query(name)) + check('full_membership_'+name,tuple(exact)==expected[name],count=len(exact)) + suggest('suggestions_cold','gate') + for _ in range(args.samples):suggest('suggestions_warm','gate') + def shared_change(add,p,*,label=None): + nonlocal shared_active + body={'target_kind':'epoch','target_uuids':list(edited),'profile_uuid':authors[p], + 'tags_add' if add else 'tags_remove':[marker],'expected_revisions':{key:shared_revisions[(key,p)] for key in edited}} + call=lambda:request('POST','/api/annotations',body=body) + value=measure(label,call)[0] if label else call() + assert value['changed']==len(edited) + for key in edited:shared_revisions[(key,p)]+=1 + shared_active=p if add else None;expected['edited']=edited if add else () + def curation_change(add,current_page,*,label): + nonlocal curation_active + body={'epoch_uuids':list(edited),'query_revision':current_page['query_revision'],'expected_binding_version':0, + 'expected_revisions':dict(curation_revisions),'changes':{'tags_add' if add else 'tags_remove':[dataset_marker]}} + measure(label,lambda:request('POST',base+'/curation',body=body)) + for key in edited:curation_revisions[key]+=1 + curation_active=add + for iteration in range(args.samples): + before=time.perf_counter();bundle('filter_A','A');bundle('filter_B','B');current=bundle('return_A','A') + samples.setdefault('A_B_A_sequential_server_bundle',[]).append(sum(samples[key][-1] for key in ('filter_A_server_bundle','filter_B_server_bundle','return_A_server_bundle'))) + p=iteration%3 + shared_change(True,p,label='shared_add_durable_save');current=bundle('first_after_shared_add','A') + page('added_tag_filter','edited');suggest('suggestions_after_shared_add','workflow') + shared_change(False,p,label='shared_remove_durable_save');current=bundle('first_after_shared_remove','A') + page('removed_tag_filter','edited');suggest('suggestions_after_shared_remove','workflow') + curation_change(True,current,label='dataset_add_durable_save');current=bundle('first_after_dataset_add','A') + curation_change(False,current,label='dataset_remove_durable_save');bundle('first_after_dataset_remove','A') + samples.setdefault('complete_workflow_wall_with_oracles',[]).append(time.perf_counter()-before) + log(json.dumps({'stage':'cycle','epochs':args.epochs,'iteration':iteration+1,'seconds':samples['complete_workflow_wall_with_oracles'][-1]})) + def profile(name,callback): + profiler=cProfile.Profile();value=profiler.runcall(callback);stats=pstats.Stats(profiler) + report.setdefault('cpu_profiles',{})[name]=[{'file':str(Path(key[0]).relative_to(root)) if Path(key[0]).is_absolute() and Path(key[0]).is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'primitive_calls':value[0],'calls':value[1],'self_seconds':value[2],'cumulative_seconds':value[3]} + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True)[:40]] + return value + if args.profile: + value=profile('warm_multitag_page',lambda:request('GET',base+'/epochs',query=query('A',limit=60)));validate_page(value,'A') + def post_save_loop(): + shared_change(True,0) + value=request('GET',base,query=query('A'));assert value['counts']['epochs']==len(expected['A']) + result=request('GET',base+'/epochs',query=query('A',limit=60));validate_page(result,'A') + request('GET','/api/annotation-tags',query={'q':'workflow','limit':12}) + profile('post_shared_save_summary_page_suggestions',post_save_loop);shared_change(False,0) + check('final_exact_membership_restored',all(tuple(service._epoch_page_identities(protocol,query(name))[0])==expected[name] for name in predicates)) + other_page=request('GET',f'/api/protocols/{other}/epochs',query={'limit':60}) + check('other_protocol_curation_untouched',all(row['curation']['revision']==1 and 'dataset:1' in row['curation']['tags'] and dataset_marker not in row['curation']['tags'] for row in other_page['epochs'])) + began=time.perf_counter();state=snapshot.load(project_root/'app-state.json');report['durable_snapshot_verify_seconds']=time.perf_counter()-began + saved={(row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation'] if row['target_kind']=='epoch' and row['target_uuid'] in edited} + check('durable_mirror_exact_tag_removal_and_author_revisions',all(sorted(saved[(key,authors[p])]['tags'])==sorted(tags(ordinals[key],p)) and saved[(key,authors[p])]['revision']==shared_revisions[(key,p)] for key in edited for p in range(3))) + check('durable_mirror_keeps_two_protocol_scopes',len(state['tables']['curation'])==args.epochs*2) + report['shared_index_stats']=getattr(getattr(shared,'_shared_tag_index',None),'stats',None) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_loaded_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values())) + report['loaded_product_modules']=loaded + finally: + if app is not None: + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow_v2.py b/docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow_v2.py new file mode 100644 index 0000000..2c4bcf2 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow_v2.py @@ -0,0 +1,329 @@ +"""Native scientist tag/filter workflow against an explicitly selected source tree. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and synchronous durable save hooks +are used. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=20);ap.add_argument('--edit-count',type=int,default=10) + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true') + ap.add_argument('--page-cells',action='store_true',help='Validate optional filtered cell counts and run the new page-first workflow') + args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<12 or args.samples<1:ap.error('Use at least12 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[], + 'page_cells':args.page_cells,'baseline_harness_sha256':digest(Path(__file__).with_name('benchmark_scientist_tag_workflow.py'))} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-scientist-tag-workflow-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + service.manifests={item['source_sha256']:{'source_path':'/synthetic/'+item['filename']} for item in service.sources} + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'];authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:shared.Annotation.insert(batch);batch=[] + if batch:shared.Annotation.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:store.Curation.insert(batch);batch=[] + if batch:store.Curation.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + predicates={ + 'A':{'all':[rule('gate:0','epoch'),rule('gate:1','epoch'),rule('cell-common','cell'),{'not':rule('gate:2')}]}, + 'B':{'any':[rule('qc','epoch'),rule('cell-bucket:3','cell'),rule('é','epoch')]}, + 'C':{'all':[{'not':rule('QC')},rule('e\u0301','epoch'),rule('cell-common','cell')]}, + 'direct_inheritance_excluded':{'all':[rule('cell-common','epoch')]}} + expected={ + 'A':tuple(ids[i] for i in range(args.epochs) if i%2==0 and i%3==0 and i%4!=0), + 'B':tuple(ids[i] for i in range(args.epochs) if i%2==1 or (i//100)%5==3 or i%3==0), + 'C':tuple(ids[i] for i in range(args.epochs) if i%2==1 and i%3!=0), + 'direct_inheritance_excluded':()} + edited=expected['A'][:args.edit_count];marker='workflow-selected';dataset_marker='workflow-dataset' + predicates['edited']={'all':[rule(marker,'epoch'),*predicates['A']['all']]};expected['edited']=() + report['filter_contract']={name:{'predicate':predicate,'expected_count':len(expected[name]),'membership_sha256':hashlib.sha256(''.join(expected[name]).encode()).hexdigest()} for name,predicate in predicates.items()} + report['edited_epoch_uuids']=edited;shared_revisions={(key,p):1 for key in edited for p in range(3)};curation_revisions={key:1 for key in edited} + shared_active=None;curation_active=False + def sql_status():return {key:int(value) for key,value in dj.conn().query("SHOW SESSION STATUS WHERE Variable_name IN ('Rows_sent','Bytes_sent','Questions')").fetchall()} + def request(method,path,*,query=None,body=None): + response=client.get(path,query_string=query) if method=='GET' else client.post(path,json=body,headers=headers) + value=response.get_json() + if response.status_code!=200:raise AssertionError((method,path,response.status_code,value)) + return value + def measure(name,callback): + before=sql_status();began=time.perf_counter();value=callback();elapsed=time.perf_counter()-began;after=sql_status() + samples.setdefault(name,[]).append(elapsed);sql_samples.setdefault(name,[]).append({key:after[key]-before[key] for key in before}) + return value,elapsed + def query(name,**extra): + return {'tag_predicate':json.dumps(predicates[name],ensure_ascii=False,separators=(',',':')), + **({'include_cells':'true'} if args.page_cells and 'limit' in extra else {}),**extra} + def validate_page(value,name,offset=0): + wanted=expected[name];shown=wanted[offset:offset+60] + assert value['total']==len(wanted) and tuple(row['epoch_uuid'] for row in value['epochs'])==shown,(name,value['total'],len(wanted)) + if args.page_cells: + counts={} + for identity in wanted: + cell=uid(args.epochs+ordinals[identity]//100);counts[cell]=counts.get(cell,0)+1 + assert {row['cell_uuid']:row['epochs'] for row in value['cells']}==counts,(name,'filtered cell counts') + assert len(value['cells'])==len(counts) + for row in value['epochs']: + identity=row['epoch_uuid'];i=ordinals[identity];wanted_chips=[] + for p,author in enumerate(authors): + values=tags(i,p)+([marker] if shared_active==p and identity in edited else []) + wanted_chips.extend((tag,author) for tag in values) + actual=sorted((item['tag'],item['profile_uuid']) for item in row['annotations']['epoch_tags']) + assert actual==sorted(wanted_chips),(name,identity,'author tag chips') + cell_i=cell_ordinals[service.rows[identity]['cell_uuid']] + wanted_inherited=sorted((tag,author) for p,author in enumerate(authors) for tag in tags(cell_i,p,cell=True)) + assert sorted((item['tag'],item['profile_uuid']) for item in row['annotations']['cell_tags'])==wanted_inherited + assert row['curation']['revision']==curation_revisions.get(identity,1) + assert sorted(row['curation']['tags'])==sorted(['dataset:0',*[f'dataset-tag:{j}' for j in range(4)]]+([dataset_marker] if curation_active and identity in edited else [])) + def page(label,name,offset=0): + value,elapsed=measure(label,lambda:request('GET',base+'/epochs',query=query(name,limit=60,offset=offset))) + validate_page(value,name,offset);return value,elapsed + def summary(label,name): + value,elapsed=measure(label,lambda:request('GET',base,query=query(name))) + assert value['counts']['epochs']==len(expected[name]),(name,value['counts'],len(expected[name]));return value,elapsed + def bundle(label,name): + _,a=summary(label+'_summary',name);value,b=page(label+'_page',name);samples.setdefault(label+'_server_bundle',[]).append(a+b);return value + def suggest(label,prefix): + value,elapsed=measure(label,lambda:request('GET','/api/annotation-tags',query={'q':prefix,'limit':12})) + if prefix=='gate': + wanted=[{'tag':f'gate:{p}','count':(args.epochs+p+1)//(p+2),'authors':[{'profile_uuid':authors[p],'display_name':author_names[p]}]} for p in range(3)] + elif prefix in ('qc','é','e\u0301','cell-common'): + all_authors=[{'profile_uuid':author,'display_name':name} for author,name in sorted(zip(authors,author_names))] + counts={'QC':(args.epochs+1)//2,'qc':args.epochs//2} if prefix=='qc' else { + prefix:(args.epochs+2)//3 if prefix=='é' else args.epochs-(args.epochs+2)//3 if prefix=='e\u0301' else (args.epochs+99)//100} + wanted=[{'tag':tag,'count':count,'authors':all_authors} for tag,count in sorted(counts.items(),key=lambda pair:(-pair[1],pair[0].casefold(),pair[0]))] + else:wanted=[] if shared_active is None else [{'tag':marker,'count':len(edited),'authors':[{'profile_uuid':authors[shared_active],'display_name':author_names[shared_active]}]}] + assert value['tags']==wanted and value['total']==len(wanted),(prefix,value,wanted) + return value + for name in predicates: + if name=='edited':continue + page('cold_filter_'+name,name) + last=max(0,len(expected[name])-60);page('oracle_boundary_'+name,name,last) + exact,_=service._epoch_page_identities(protocol,query(name)) + check('full_membership_'+name,tuple(exact)==expected[name],count=len(exact)) + suggest('suggestions_cold','gate') + for _ in range(args.samples):suggest('suggestions_warm','gate') + if args.page_cells: + for label,prefix in [('case','qc'),('unicode_nfc','é'),('unicode_nfd','e\u0301'),('inherited_targets','cell-common')]: + suggest('suggestions_first_'+label,prefix) + known_fields={'epoch','date','cell','block','block time','cell type','group label','group','protocol', + 'parameters/contrast','parameters/seed','parameters/stimTime','parameters/currentMean', + 'metadata/cell/properties/type','metadata/cell/label','metadata/block/parameters/amp'} + allowed_fields={'id','label','category','path','components','grouping_role','grouping_priority','grouping_hint'} + for iteration in range(args.samples+1): + value,_=measure('metadata_fields_cold' if iteration==0 else 'metadata_fields_warm',lambda:request('GET','/api/metadata/fields')) + assert {field['id'] for field in value['fields']}==known_fields + assert len(value['fields'])==len(known_fields) and all(set(field)<=allowed_fields for field in value['fields']) + def shared_change(add,p,*,label=None): + nonlocal shared_active + body={'target_kind':'epoch','target_uuids':list(edited),'profile_uuid':authors[p], + 'tags_add' if add else 'tags_remove':[marker],'expected_revisions':{key:shared_revisions[(key,p)] for key in edited}} + call=lambda:request('POST','/api/annotations',body=body) + value=measure(label,call)[0] if label else call() + assert value['changed']==len(edited) + for key in edited:shared_revisions[(key,p)]+=1 + shared_active=p if add else None;expected['edited']=edited if add else () + def curation_change(add,current_page,*,label): + nonlocal curation_active + body={'epoch_uuids':list(edited),'query_revision':current_page['query_revision'],'expected_binding_version':0, + 'expected_revisions':dict(curation_revisions),'changes':{'tags_add' if add else 'tags_remove':[dataset_marker]}} + measure(label,lambda:request('POST',base+'/curation',body=body)) + for key in edited:curation_revisions[key]+=1 + curation_active=add + for iteration in range(args.samples): + before=time.perf_counter();bundle('filter_A','A');bundle('filter_B','B');current=bundle('return_A','A') + samples.setdefault('A_B_A_sequential_server_bundle',[]).append(sum(samples[key][-1] for key in ('filter_A_server_bundle','filter_B_server_bundle','return_A_server_bundle'))) + p=iteration%3 + shared_change(True,p,label='shared_add_durable_save');current=bundle('first_after_shared_add','A') + page('added_tag_filter','edited');suggest('suggestions_after_shared_add','workflow') + shared_change(False,p,label='shared_remove_durable_save');current=bundle('first_after_shared_remove','A') + page('removed_tag_filter','edited');suggest('suggestions_after_shared_remove','workflow') + curation_change(True,current,label='dataset_add_durable_save');current=bundle('first_after_dataset_add','A') + curation_change(False,current,label='dataset_remove_durable_save');bundle('first_after_dataset_remove','A') + samples.setdefault('complete_workflow_wall_with_oracles',[]).append(time.perf_counter()-before) + log(json.dumps({'stage':'cycle','epochs':args.epochs,'iteration':iteration+1,'seconds':samples['complete_workflow_wall_with_oracles'][-1]})) + # This is measured separately: the first request after a save is + # the visible page, before any summary/autocomplete can maintain + # or warm the shared membership index for it. + if args.page_cells: + def focused(label): + identity=edited[0];i=ordinals[identity] + value,_=measure(label,lambda:request('GET','/api/epochs/'+identity,query={'protocol_uuid':protocol})) + assert value['epoch_uuid']==identity and value['parameters']=={'contrast':(i%5)/10,'seed':i,'stimTime':1000,'currentMean':(i%3)*100} + assert value['curation']['revision']==curation_revisions[identity] + wanted=sorted((tag,author) for p,author in enumerate(authors) for tag in tags(i,p)+([marker] if shared_active==p else [])) + assert sorted((item['tag'],item['profile_uuid']) for item in value['annotations']['epoch_tags'])==wanted + for iteration in range(args.samples): + page('page_first_filter_A','A');page('page_first_filter_B','B');current,_=page('page_first_return_A','A') + p=iteration%3 + shared_change(True,p,label='page_first_shared_add_save') + current,_=page('page_first_after_shared_add','A') + focused('focused_metadata_after_shared_add') + suggest('page_first_suggestions_after_shared_add','workflow') + shared_change(False,p,label='page_first_shared_remove_save') + current,_=page('page_first_after_shared_remove','A') + focused('focused_metadata_after_shared_remove') + suggest('page_first_suggestions_after_shared_remove','workflow') + curation_change(True,current,label='page_first_dataset_add_save') + current,_=page('page_first_after_dataset_add','A') + focused('focused_metadata_after_dataset_add') + curation_change(False,current,label='page_first_dataset_remove_save') + page('page_first_after_dataset_remove','A') + focused('focused_metadata_after_dataset_remove') + log(json.dumps({'stage':'page_first_cycle','epochs':args.epochs,'iteration':iteration+1})) + def profile(name,callback): + profiler=cProfile.Profile();value=profiler.runcall(callback);stats=pstats.Stats(profiler) + report.setdefault('cpu_profiles',{})[name]=[{'file':str(Path(key[0]).relative_to(root)) if Path(key[0]).is_absolute() and Path(key[0]).is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'primitive_calls':value[0],'calls':value[1],'self_seconds':value[2],'cumulative_seconds':value[3]} + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True)[:40]] + return value + if args.profile: + value=profile('warm_multitag_page',lambda:request('GET',base+'/epochs',query=query('A',limit=60)));validate_page(value,'A') + def post_save_loop(): + shared_change(True,0) + value=request('GET',base,query=query('A'));assert value['counts']['epochs']==len(expected['A']) + result=request('GET',base+'/epochs',query=query('A',limit=60));validate_page(result,'A') + request('GET','/api/annotation-tags',query={'q':'workflow','limit':12}) + profile('post_shared_save_summary_page_suggestions',post_save_loop);shared_change(False,0) + check('final_exact_membership_restored',all(tuple(service._epoch_page_identities(protocol,query(name))[0])==expected[name] for name in predicates)) + other_page=request('GET',f'/api/protocols/{other}/epochs',query={'limit':60}) + check('other_protocol_curation_untouched',all(row['curation']['revision']==1 and 'dataset:1' in row['curation']['tags'] and dataset_marker not in row['curation']['tags'] for row in other_page['epochs'])) + report['workflow_peak_rss_before_durable_oracle_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + began=time.perf_counter();state=snapshot.load(project_root/'app-state.json');report['durable_snapshot_verify_seconds']=time.perf_counter()-began + saved={(row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation'] if row['target_kind']=='epoch' and row['target_uuid'] in edited} + check('durable_mirror_exact_tag_removal_and_author_revisions',all(sorted(saved[(key,authors[p])]['tags'])==sorted(tags(ordinals[key],p)) and saved[(key,authors[p])]['revision']==shared_revisions[(key,p)] for key in edited for p in range(3))) + check('durable_mirror_keeps_two_protocol_scopes',len(state['tables']['curation'])==args.epochs*2) + report['shared_index_stats']=getattr(getattr(shared,'_shared_tag_index',None),'stats',None) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_loaded_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values())) + report['loaded_product_modules']=loaded + finally: + if app is not None: + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + derived={ + 'warm_page_only_A_B_A_inferred_from_summary_first':('filter_A_page','filter_B_page','return_A_page'), + 'shared_add_save_plus_warm_page_inferred':('shared_add_durable_save','first_after_shared_add_page'), + 'shared_remove_save_plus_warm_page_inferred':('shared_remove_durable_save','first_after_shared_remove_page'), + 'measured_page_first_A_B_A':('page_first_filter_A','page_first_filter_B','page_first_return_A'), + 'measured_shared_add_save_plus_first_page':('page_first_shared_add_save','page_first_after_shared_add'), + 'measured_shared_remove_save_plus_first_page':('page_first_shared_remove_save','page_first_after_shared_remove'), + 'measured_shared_add_save_page_focus':('page_first_shared_add_save','page_first_after_shared_add','focused_metadata_after_shared_add'), + 'measured_shared_remove_save_page_focus':('page_first_shared_remove_save','page_first_after_shared_remove','focused_metadata_after_shared_remove'), + 'measured_dataset_add_save_plus_first_page':('page_first_dataset_add_save','page_first_after_dataset_add'), + 'measured_dataset_remove_save_plus_first_page':('page_first_dataset_remove_save','page_first_after_dataset_remove')} + report['derived_bundle_definitions']={name:list(keys) for name,keys in derived.items() if all(key in samples for key in keys)} + for name,keys in report['derived_bundle_definitions'].items(): + lengths={len(samples[key]) for key in keys} + if len(lengths)==1:samples[name]=[sum(values) for values in zip(*(samples[key] for key in keys))] + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['harness_unchanged']=digest(__file__)==report['harness_sha256'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and report['harness_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py b/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py new file mode 100644 index 0000000..bfc07b5 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py @@ -0,0 +1,135 @@ +"""Disposable current disk-index service probe; no SQL, lab files, or mutations. + +Run with PYTHONPATH=python .rieke-runtime/venv/bin/python + --epochs 10000 --output +Timings cover service CPU/I/O only, excluding HTTP hooks and browser rendering. +""" +from __future__ import annotations +import argparse +from collections.abc import Mapping +import cProfile +import datetime as dt +import gc +import hashlib +import json +from pathlib import Path +import pstats +import platform +import statistics +import tempfile +import time +import uuid +import psutil +from workspace_disk_index import DiskMetadataIndex +from workspace_service import WorkspaceService +from workspace_tree_pages import TreePages + + +def uid(number): + # Deterministic pseudorandom UUIDs avoid unrealistically cheap wire compression. + return str(uuid.UUID(bytes=hashlib.sha256(str(number).encode()).digest()[:16])) + + +class Details(Mapping): + def __init__(self, rows): self.rows = rows + def __len__(self): return len(self.rows) + def __iter__(self): return iter(self.rows) + def __getitem__(self, key): + row = self.rows[key]; i = row['synthetic_index'] + return {'parameters': {'contrast': (i % 5) / 10, 'seed': i, + 'stimTime': 1000, 'currentMean': (i % 3) * 100}, 'properties': {}, + 'attributes': {}, 'metadata': {'cell': {'uuid': row['cell_uuid'], + 'label': row['cell_label'], 'properties': {'type': row['cell_type']}}, + 'block': {'uuid': row['block_uuid'], 'parameters': {'amp': 'Amp1'}}}} + + +def fixture(count): + service = WorkspaceService.__new__(WorkspaceService) + service._loaded = True; service.curation_provider = None + service.project = {'project_uuid': uid(-1), 'name': 'Disposable scale probe'} + service.config = {'database': 'no-sql'} + service.sources = [{'source_sha256': f'{i+1:064x}', 'filename': f'synthetic-{i}.h5'} for i in range(10)] + service.rows = {}; service.cells = {} + base = dt.datetime(2026, 9, 1, 12) + for i in range(count): + identity = uid(i); cell = uid(count+i//100); block = uid(2*count+i//20) + started = (base + dt.timedelta(seconds=i)).strftime('%m/%d/%Y %H:%M:%S:%f') + row = {'epoch_uuid': identity, 'cell_uuid': cell, 'cell_label': f'Cell{i//100}', + 'cell_type': ['ON', 'OFF'][(i//100)%2], 'date': '2026-09-01', 'start_time': started, + 'group_uuid': uid(3*count), 'group_label': 'Control', 'block_uuid': block, + 'block_start_time': started, 'protocol_name': 'Synthetic', 'duration_seconds': 1., + 'epoch_number': i%20+1, 'streams': [], 'source_sha256': service.sources[(i//100)%10]['source_sha256'], + 'metadata_hash': 'b'*64, 'synthetic_index': i} + service.rows[identity] = row + service.cells[cell] = {'cell_uuid': cell, 'label': row['cell_label'], 'cell_type': row['cell_type'], 'date': row['date']} + protocol = uid(-2) + service.protocols = {protocol: {'definition': {'protocol_uuid': protocol, 'name': 'All epochs', 'query': {'version':1, 'all':[]}}, + 'result': {'protocol_uuid': protocol, 'protocol_name': 'Synthetic', + 'epochs': [{'uuid': key, 'metadata_hash': 'b'*64} for key in service.rows], + 'cells': [{'uuid': key} for key in service.cells], 'source_revisions': [s['source_sha256'] for s in service.sources]}}} + service._fingerprints = {key:'b'*64 for key in service.rows} + service.events = lambda limit=25: [] + return service, protocol + + +def run(count, repeats): + process = psutil.Process() + rss = lambda: round(process.memory_info().rss/1024**2, 2) + report = {'epochs':count, 'sources':10, 'protocol_members':count, 'synthetic':True, + 'python':platform.python_version(), 'platform':platform.platform(), + 'limits':'No SQL, API snapshot hooks, HTTP, tags, waveform data, or browser; 4 scalar parameters per epoch.', + 'rss_initial_mib':rss(), 'operations':[]} + service, protocol = fixture(count) + with tempfile.TemporaryDirectory(prefix='rieke-service-scale-') as directory: + started = time.perf_counter() + index = DiskMetadataIndex.build(Path(directory)/'index.sqlite', service.rows, Details(service.rows), service.sources, 'synthetic-generation', service.project['project_uuid']) + report.update(build_seconds=time.perf_counter()-started, index_bytes=index.path.stat().st_size, + fields=len(index.catalog()['fields']), rss_model_index_mib=rss()) + service.disk_index = index; service.details = index.details + pager = TreePages(service) + predicate = {'field':'parameters/contrast','operator':'eq','value':.3} + operations = [ + ('epoch_page_60', lambda:service.epoch_page(protocol, limit=60)), + ('epoch_page_60_filter_one_cell', lambda:service.epoch_page(protocol, {'cell_uuid':next(iter(service.cells))}, limit=60)), + ('tree_root_page_80', lambda:pager.page({'splits':'cell,block','limit':80})), + ('flat_tree_page_80', lambda:pager.page({'splits':'','limit':80})), + ('select_one_epoch_predicate', lambda:service.match_predicate({'field':'epoch','operator':'eq','value':next(iter(service.rows))})), + ('filter_preview_summary', lambda:service.explore_preview(predicate, 'cell,block', include_tree=False)), + ('filter_preview_fast_summary', lambda:service.explore_preview(predicate, 'cell,block', include_tree=False, include_catalog_summary=False)), + ('overview', service.overview)] + for name, operation in operations: + samples = []; cpu_samples = [] + for _ in range(repeats): + gc.collect(); cpu = time.process_time(); started = time.perf_counter() + result = operation() + samples.append(time.perf_counter()-started); cpu_samples.append(time.process_time()-cpu) + started = time.perf_counter(); encoded = json.dumps(result, separators=(',',':')).encode() + serialization = time.perf_counter()-started + record = {'name':name,'wall_seconds_samples':samples, 'median_seconds':statistics.median(samples), + 'median_cpu_seconds':statistics.median(cpu_samples), 'json_bytes':len(encoded), + 'serialization_seconds':serialization,'rss_mib':rss()} + if isinstance(result,dict): + for key in ('total','matched_count','count'): + if key in result: record[key]=result[key] + if name in ('tree_root_page_80','filter_preview_summary','select_one_epoch_predicate'): + profile=cProfile.Profile();profile.enable();operation();profile.disable() + stats=pstats.Stats(profile) + record['profile_top_cumulative']=[{'file':Path(key[0]).name,'line':key[1], + 'function':key[2],'primitive_calls':value[0],'calls':value[1], + 'self_seconds':value[2],'cumulative_seconds':value[3]} + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True)[:18]] + report['operations'].append(record) + print(json.dumps({'epochs':count,**record},default=str),flush=True) + del result, encoded + report['rss_after_operations_mib']=rss() + return report + + +if __name__ == '__main__': + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs',type=int,required=True) + parser.add_argument('--repeats',type=int,default=3) + parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args() + result=run(args.epochs,args.repeats) + args.output.write_text(json.dumps(result,indent=2)) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_single_tag_write.py b/docs/dev/scale-audit-2026-09-29/benchmark_single_tag_write.py new file mode 100644 index 0000000..34f7662 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_single_tag_write.py @@ -0,0 +1,247 @@ +"""Native single-epoch and single-cell writes without post-seed index preparation. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and each version's save hooks +are used. Native SQL commits are checked immediately; any background recovery +mirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=20);ap.add_argument('--targets',default='epoch:1,cell:1') + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true') + ap.add_argument('--page-cells',action='store_true',default=True) + args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<200 or args.samples<1:ap.error('Use at least200 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[], + 'page_cells':True,'target_specification':args.targets,'baseline_harness_sha256':digest(Path(__file__).with_name('benchmark_scientist_tag_workflow.py'))} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-single-tag-write-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + service.manifests={item['source_sha256']:{'source_path':'/synthetic/'+item['filename']} for item in service.sources} + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'];authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:shared.Annotation.insert(batch);batch=[] + if batch:shared.Annotation.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:store.Curation.insert(batch);batch=[] + if batch:store.Curation.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + + + + import inspect,threading + from workspace_shared_tag_index import SharedTagIndex + lock=inspect.getclosurevars(app.view_functions['annotation_batch_read']).nonlocals['db_lock'] + connection=dj.conn();owner=threading.get_ident();recording=False;trace={} + original_start=connection.start_transaction;original_commit=connection.commit_transaction + original_event=shared._event;original_membership=shared._membership_index;original_refresh=SharedTagIndex.refresh + def current():return recording and threading.get_ident()==owner + def start_txn(): + began=time.perf_counter();value=original_start() + if current():trace['transaction_started']=began;trace['begins']+=1 + return value + def commit_txn(): + began=time.perf_counter();value=original_commit() + if current(): + trace['commit_seconds'].append(time.perf_counter()-began) + trace['transaction_seconds'].append(time.perf_counter()-trace['transaction_started']);trace['commits']+=1 + return value + def event(*args,**kwargs): + if current(): + assert connection.in_transaction and trace['begins']==1 and trace['commits']==0 + trace['events_inside_transaction']+=1 + return original_event(*args,**kwargs) + def membership(*args,**kwargs): + if current():trace['membership_calls']+=1 + return original_membership(*args,**kwargs) + def refresh(*args,**kwargs): + if current():trace['index_refresh_calls']+=1 + return original_refresh(*args,**kwargs) + connection.start_transaction=start_txn;connection.commit_transaction=commit_txn + shared._event=event;shared._membership_index=membership;SharedTagIndex.refresh=refresh + with lock: + values=connection.query('SELECT @@innodb_flush_log_at_trx_commit,@@sync_binlog,@@log_bin').fetchone() + report['mysql_durability']={'innodb_flush_log_at_trx_commit':int(values[0]),'sync_binlog':int(values[1]),'log_bin':bool(values[2])} + epoch=ids[0];cell=service.rows[epoch]['cell_uuid'];children=tuple(key for key in ids if service.rows[key]['cell_uuid']==cell) + targets={'epoch':epoch,'cell':cell};revisions={(kind,p):1 for kind in targets for p in range(3)};active={};marker='single-write-marker' + report['post_traces']=[];report['backup_receipts']=[] + index_before=getattr(shared,'_shared_tag_index',None) + report['index_before_posts']={'present':index_before is not None,'stats':dict(index_before.stats) if index_before else None,'post_seed_preparation':False} + def wanted(kind,p):return sorted(tags(ordinals[epoch] if kind=='epoch' else cell_ordinals[cell],p,cell=kind=='cell')+([marker] if active.get(kind)==p else [])) + def child_rows(): + with lock:rows=(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'}&[{'target_uuid':key} for key in children]).to_dicts() + return sorted((row['target_uuid'],row['profile_uuid'],row['revision'],tuple(sorted(row['tags'])),str(row['updated_at'])) for row in rows) + def post(label,kind,p,add): + nonlocal recording,trace + key=targets[kind];before_children=child_rows() if kind=='cell' else None + body={'target_kind':kind,'target_uuids':[key],'profile_uuid':authors[p], + 'tags_add':[marker] if add else [],'tags_remove':[] if add else [marker], + 'expected_revisions':{key:revisions[(kind,p)]}} + trace={'operation':label,'begins':0,'commits':0,'events_inside_transaction':0,'membership_calls':0,'index_refresh_calls':0,'commit_seconds':[],'transaction_seconds':[]} + recording=True;began=time.perf_counter() + try:response=client.post('/api/annotations',json=body,headers=headers);value=response.get_json() + finally:elapsed=time.perf_counter()-began;recording=False + assert response.status_code==200 and value['changed']==1,(response.status_code,value) + assert value['persistence']['database']=='committed' + assert trace['begins']==trace['commits']==trace['events_inside_transaction']==1,trace + assert trace['membership_calls']==trace['index_refresh_calls']==0,trace + trace.pop('transaction_started',None);report['post_traces'].append(trace);report['backup_receipts'].append(value['persistence']) + samples.setdefault(label,[]).append(elapsed) + samples.setdefault(label+'_sql_transaction',[]).append(trace['transaction_seconds'][0]);samples.setdefault(label+'_commit_roundtrip',[]).append(trace['commit_seconds'][0]) + revisions[(kind,p)]+=1 + if add:active[kind]=p + else:active.pop(kind,None) + receipt=value['targets'][key] + assert receipt['revisions']=={author:revisions[(kind,q)] for q,author in enumerate(authors)} + assert sorted((v['tag'],v['profile_uuid']) for v in receipt['tags'])==sorted((tag,author) for q,author in enumerate(authors) for tag in wanted(kind,q)) + with lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':kind,'target_uuid':key,'profile_uuid':authors[p]}).to_dicts() + events=(shared.Event&{'event_uuid':value['event_uuid']}).to_dicts() + assert len(rows)==len(events)==1 and rows[0]['revision']==revisions[(kind,p)] and sorted(rows[0]['tags'])==wanted(kind,p) + assert events[0]['action']=='shared_annotations_updated' and events[0]['payload']['target_count']==1 + assert events[0]['payload']['after'][0]['target_uuid']==key and events[0]['payload']['after'][0]['revision']==revisions[(kind,p)] + if kind=='cell':assert child_rows()==before_children,'Cell save rewrote child annotation rows' + # Both first writes happen before repeated samples, with no + # post-seed index rebuild or filter request anywhere in this run. + for kind in targets:post(kind+'_first_add',kind,0,True) + for kind in targets:post(kind+'_first_remove',kind,0,False) + log(json.dumps({'stage':'first_writes','epochs':args.epochs,'epoch_ms':samples['epoch_first_add'][0]*1000,'cell_ms':samples['cell_first_add'][0]*1000})) + for kind in targets: + for iteration in range(args.samples): + post(kind+'_add',kind,iteration%3,True);post(kind+'_remove',kind,iteration%3,False) + log(json.dumps({'stage':'single_target_complete','epochs':args.epochs,'target':kind,'samples':args.samples})) + connection.start_transaction=original_start;connection.commit_transaction=original_commit + shared._event=original_event;shared._membership_index=original_membership;SharedTagIndex.refresh=original_refresh + check('no_membership_index_or_refresh_during_any_post',all(row['membership_calls']==row['index_refresh_calls']==0 for row in report['post_traces']),posts=len(report['post_traces'])) + check('annotation_event_committed_in_same_transaction',all(row['begins']==row['commits']==row['events_inside_transaction']==1 for row in report['post_traces'])) + after_index=getattr(shared,'_shared_tag_index',None);report['index_after_posts']={'stats':dict(after_index.stats) if after_index else None} + scheduler=app.extensions['backup_scheduler'];scheduler.flush();report['final_backup_status']=scheduler.status() + state=snapshot.load(project_root/'app-state.json');saved={(row['target_kind'],row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation']} + for (kind,p),revision in revisions.items(): + row=saved[(kind,targets[kind],authors[p])];assert row['revision']==revision and sorted(row['tags'])==wanted(kind,p) + check('final_recovery_mirror_exact_tags_and_revisions',True) + check('cell_has_one_canonical_record_per_author_no_child_copies',sum(row['target_kind']=='epoch' for row in saved.values())==args.epochs*3,child_epochs=len(children)) + check('other_protocol_curation_untouched',len(state['tables']['curation'])==args.epochs*2 and all(row['revision']==1 for row in state['tables']['curation'])) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values()));report['loaded_product_modules']=loaded + finally: + if app is not None: + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush() + close=getattr(scheduler,'close',None) + if close is not None:close(flush=False) + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['harness_unchanged']=digest(__file__)==report['harness_sha256'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and report['harness_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_tag_actions.py b/docs/dev/scale-audit-2026-09-29/benchmark_tag_actions.py new file mode 100644 index 0000000..e3a30dc --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_tag_actions.py @@ -0,0 +1,284 @@ +"""Native single, batch and inherited-cell tag actions against a selected source tree. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and synchronous durable save hooks +are used. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=20);ap.add_argument('--targets',default='epoch:1,epoch:5,epoch:20,cell:1') + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true') + ap.add_argument('--page-cells',action='store_true',default=True) + args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<12 or args.samples<1:ap.error('Use at least12 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[], + 'page_cells':True,'target_specification':args.targets,'baseline_harness_sha256':digest(Path(__file__).with_name('benchmark_scientist_tag_workflow.py'))} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-tag-actions-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + service.manifests={item['source_sha256']:{'source_path':'/synthetic/'+item['filename']} for item in service.sources} + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'];authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:shared.Annotation.insert(batch);batch=[] + if batch:shared.Annotation.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:store.Curation.insert(batch);batch=[] + if batch:store.Curation.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + + targets=[] + for entry in args.targets.split(','): + kind,count=entry.split(':');count=int(count) + if kind not in ('epoch','cell') or count<1 or (kind=='cell' and count!=1):raise ValueError('Use epoch:N or cell:1') + selected=ids[:count] if kind=='epoch' else (next(iter(service.cells)),) + if len(selected)!=count:raise ValueError('Not enough targets') + targets.append({'name':f'{kind}_{count}','kind':kind,'ids':tuple(selected),'marker':f'action-{kind}-{count}'}) + report['targets']=[{**target,'child_epoch_count':sum(service.rows[key]['cell_uuid'] in target['ids'] for key in ids) if target['kind']=='cell' else len(target['ids'])} for target in targets] + revisions={(target['kind'],identity,p):1 for target in targets for identity in target['ids'] for p in range(3)} + active=None + stable_predicate={'all':[rule('gate:0','epoch'),rule('gate:1','epoch'),rule('cell-common','cell'),{'not':rule('gate:2')}]} + stable_expected=tuple(ids[i] for i in range(args.epochs) if i%2==0 and i%3==0 and i%4!=0) + def sql_status():return {key:int(value) for key,value in dj.conn().query("SHOW SESSION STATUS WHERE Variable_name IN ('Rows_sent','Bytes_sent','Questions')").fetchall()} + def request(method,path,*,query=None,body=None): + response=client.get(path,query_string=query) if method=='GET' else client.post(path,json=body,headers=headers) + value=response.get_json() + if response.status_code!=200:raise AssertionError((method,path,response.status_code,value)) + return value + def measure(name,callback): + before=sql_status();began=time.perf_counter();value=callback();elapsed=time.perf_counter()-began;after=sql_status() + samples.setdefault(name,[]).append(elapsed);sql_samples.setdefault(name,[]).append({key:after[key]-before[key] for key in before}) + return value,elapsed + def query(predicate,**extra):return {'tag_predicate':json.dumps(predicate,ensure_ascii=False,separators=(',',':')),**extra} + def wanted_tags(kind,identity,p): + ordinal=ordinals[identity] if kind=='epoch' else cell_ordinals[identity] + result=tags(ordinal,p,cell=kind=='cell') + if active is not None and active[0]['kind']==kind and identity in active[0]['ids'] and active[1]==p:result=result+[active[0]['marker']] + return sorted(result) + def validate_row(row): + identity=row['epoch_uuid'];cell=service.rows[identity]['cell_uuid'] + for kind,field,key in [('epoch','epoch_tags',identity),('cell','cell_tags',cell)]: + wanted=sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,key,p)) + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['annotations'][field])==wanted,(identity,kind) + assert row['curation']['revision']==1 + assert sorted(row['curation']['tags'])==sorted(['dataset:0',*[f'dataset-tag:{j}' for j in range(4)]]) + def page(label,predicate,wanted,offset=0,*,timed=True): + call=lambda:request('GET',base+'/epochs',query=query(predicate,limit=60,offset=offset,include_cells='true')) + value,elapsed=measure(label,call) if timed else (call(),0) + assert value['total']==len(wanted) + assert tuple(row['epoch_uuid'] for row in value['epochs'])==wanted[offset:offset+60] + counts={} + for key in wanted: + cell=service.rows[key]['cell_uuid'];counts[cell]=counts.get(cell,0)+1 + assert {row['cell_uuid']:row['epochs'] for row in value['cells']}==counts + for row in value['epochs']:validate_row(row) + return value,elapsed + def focused(label,identity): + value,elapsed=measure(label,lambda:request('GET','/api/epochs/'+identity,query={'protocol_uuid':protocol})) + assert value['epoch_uuid']==identity;validate_row(value);return value,elapsed + def affected_ids(target): + return target['ids'] if target['kind']=='epoch' else tuple(key for key in ids if service.rows[key]['cell_uuid'] in target['ids']) + def change(target,add,p,*,label=None): + nonlocal active + body={'target_kind':target['kind'],'target_uuids':list(target['ids']),'profile_uuid':authors[p], + 'tags_add' if add else 'tags_remove':[target['marker']], + 'expected_revisions':{key:revisions[(target['kind'],key,p)] for key in target['ids']}} + call=lambda:request('POST','/api/annotations',body=body) + value=measure(label,call)[0] if label else call() + assert value['changed']==len(target['ids']) + for key in target['ids']:revisions[(target['kind'],key,p)]+=1 + active=(target,p) if add else None + return value + def sql_rows(kind,keys): + rows=(shared.Annotation&{'project_uuid':project,'target_kind':kind}&[{'target_uuid':key} for key in keys]).to_dicts() + return sorted((row['target_uuid'],row['profile_uuid'],row['revision'],tuple(sorted(row['tags'])),row['author_name'],str(row['updated_at'])) for row in rows) + initial_epoch_row_count=len(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'}) + check('three_direct_annotation_rows_per_epoch',initial_epoch_row_count==args.epochs*3) + page('cold_initial_shared_index',stable_predicate,stable_expected) + exact,_=service._epoch_page_identities(protocol,query(stable_predicate));check('stable_filter_exact_membership',tuple(exact)==stable_expected,count=len(exact)) + # Warm the empty marker predicates once. Every later add/remove + # must invalidate and recompute the affected predicate exactly. + for target in targets:page('warm_empty_'+target['name'],{'all':[rule(target['marker'])]},(),timed=False) + for target in targets: + wanted=affected_ids(target);focus=wanted[0];predicate={'all':[rule(target['marker'])]} + child_rows=sql_rows('epoch',wanted) if target['kind']=='cell' else None + for iteration in range(args.samples): + p=iteration%3 + for add in (True,False): + label=target['name']+('_add' if add else '_remove') + change(target,add,p,label=label+'_durable_save') + page(label+'_first_stable_page',stable_predicate,stable_expected) + focused(label+'_focused_metadata',focus) + expected=wanted if add else () + page(label+'_affected_filter',predicate,expected) + exact,_=service._epoch_page_identities(protocol,query(predicate));assert tuple(exact)==expected + if len(expected)>60:page(label+'_affected_last_page',predicate,expected,len(expected)-60,timed=False) + if target['kind']=='cell': + direct={'all':[rule(target['marker'],'epoch')]} + page(label+'_direct_epoch_excludes_inheritance',direct,(),timed=False) + assert sql_rows('epoch',wanted)==child_rows,'Cell edit changed child annotation rows' + assert len(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'})==initial_epoch_row_count,'Cell edit created epoch annotation copies' + for key in target['ids']: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':target['kind'],'target_uuid':key,'profile_uuid':authors[p]}).to_dicts() + assert len(rows)==1 and rows[0]['revision']==revisions[(target['kind'],key,p)] + assert sorted(rows[0]['tags'])==wanted_tags(target['kind'],key,p) + samples.setdefault(label+'_save_plus_first_page',[]).append(samples[label+'_durable_save'][-1]+samples[label+'_first_stable_page'][-1]) + samples.setdefault(label+'_save_page_focus',[]).append(samples[label+'_save_plus_first_page'][-1]+samples[label+'_focused_metadata'][-1]) + log(json.dumps({'stage':'action_cycle','epochs':args.epochs,'target':target['name'],'iteration':iteration+1})) + check('exact_add_remove_'+target['name'],True,samples=args.samples,targets=len(target['ids']),effective_epochs=len(wanted)) + if target['kind']=='cell':check('cell_inheritance_without_child_annotation_copy',True,child_epochs=len(wanted),direct_rows_unchanged=len(child_rows)) + def profile_save(target,add): + import re + connection=dj.conn();original_query=connection.query;original_fsync=os.fsync;sql_calls=[];sync_calls=[] + def traced_query(statement,*positional,**keywords): + began=time.perf_counter() + try:return original_query(statement,*positional,**keywords) + finally:sql_calls.append({'sql_shape':re.sub(r"'[^']*'","'?'",str(statement))[:240],'seconds':time.perf_counter()-began}) + def traced_fsync(descriptor): + began=time.perf_counter() + try:return original_fsync(descriptor) + finally:sync_calls.append(time.perf_counter()-began) + profiler=cProfile.Profile();connection.query=traced_query;os.fsync=traced_fsync + try:profiler.runcall(change,target,add,0) + finally:connection.query=original_query;os.fsync=original_fsync + stats=pstats.Stats(profiler);rows=[] + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True): + path=Path(key[0]);rows.append({'file':str(path.relative_to(root)) if path.is_absolute() and path.is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'primitive_calls':value[0],'calls':value[1],'self_seconds':value[2],'cumulative_seconds':value[3]}) + label=target['name']+('_add' if add else '_remove') + report.setdefault('cpu_profiles',{})[label]={'top_functions':rows[:100], + 'sql_and_durability_functions':[row for row in rows if any(word in row['function'].lower() for word in ('fsync','commit','query','execute','capture','recovery','atomic_write'))], + 'native_sql_calls':sql_calls,'python_fsync_calls_seconds':sync_calls, + 'limits':'Separate instrumented sample. Native SQL timing wraps query dispatch; fetch costs appear in cProfile. Python fsync does not intercept SQLite internal fsync; SQLite commit time appears in cProfile.'} + page(label+'_profile_postcheck',stable_predicate,stable_expected,timed=False) + if args.profile: + for target in targets: + for add in (True,False):profile_save(target,add) + check('final_markers_removed',active is None) + report['workflow_peak_rss_before_durable_oracle_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + began=time.perf_counter();state=snapshot.load(project_root/'app-state.json');report['durable_snapshot_verify_seconds']=time.perf_counter()-began + saved={(row['target_kind'],row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation']} + for (kind,key,p),revision in revisions.items(): + row=saved[(kind,key,authors[p])] + assert row['revision']==revision and sorted(row['tags'])==wanted_tags(kind,key,p) + check('durable_mirror_exact_targets_revisions_and_removal',True,records=len(revisions)) + check('durable_mirror_direct_row_count_unchanged',sum(row['target_kind']=='epoch' for row in saved.values())==args.epochs*3) + check('independent_protocol_curation_untouched',len(state['tables']['curation'])==args.epochs*2 and all(row['revision']==1 for row in state['tables']['curation'])) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_loaded_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values())) + report['loaded_product_modules']=loaded + finally: + if app is not None: + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['harness_unchanged']=digest(__file__)==report['harness_sha256'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and report['harness_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_tag_collation.py b/docs/dev/scale-audit-2026-09-29/benchmark_tag_collation.py new file mode 100644 index 0000000..5b82f2b --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_tag_collation.py @@ -0,0 +1,122 @@ +"""Disposable same-server old/new trigger validation timing; no UI timing claim.""" +import hashlib,json,statistics,tempfile,time,uuid +from pathlib import Path +import pymysql +from test_workspace_state_generation import NativeConnection +import workspace_native_tag_lookup as lookup_module +from workspace_projects import create_project +import workspace_native_mysql as native + + +def baseline_manifest(): + def valid(alias): + tag=lookup_module._tag(alias) + whitespace=[chr(n).encode('utf-8').hex() for n in range(0x3001) if chr(n).isspace()] + ends=','.join('0x'+value for value in whitespace) + controls=' OR '.join(f'LOCATE(CHAR({n}),{tag})>0' for n in range(32)) + invalid=(f"JSON_TYPE(JSON_EXTRACT({alias}.tags,CONCAT('$[',j.ordinal-1,']')))!='STRING' " + f'OR CHAR_LENGTH({tag}) NOT BETWEEN 1 AND 255 OR BINARY LEFT({tag},1) IN ({ends}) ' + f'OR BINARY RIGHT({tag},1) IN ({ends}) OR {controls}') + return (f"IF JSON_TYPE({alias}.tags)!='ARRAY' OR JSON_LENGTH({alias}.tags)>100 OR EXISTS (" + f"SELECT 1 FROM JSON_TABLE({alias}.tags,'$[*]' COLUMNS(ordinal FOR ORDINALITY)) j WHERE {invalid}) " + "THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Invalid canonical shared annotation tags'; END IF;") + def insert(alias): + return (valid(alias)+f' INSERT INTO `{lookup_module.SCHEMA}`.`{lookup_module.TABLE}` ({",".join(lookup_module.COLUMNS)}) ' + f'SELECT {alias}.project_uuid,{alias}.target_kind,{alias}.target_uuid,{alias}.profile_uuid,' + f"CAST({lookup_module._tag(alias)} AS BINARY) FROM JSON_TABLE({alias}.tags,'$[*]' " + "COLUMNS(ordinal FOR ORDINALITY)) j;") + delete,dirty=lookup_module._delete,lookup_module._dirty + return {lookup_module.PREFIX+suffix:{'table':'shared_annotation','event':event,'timing':'AFTER','body':'BEGIN '+body+' END'} + for suffix,event,body in [('ai','INSERT',insert('NEW')+' '+dirty('NEW')), + ('au','UPDATE',delete('OLD')+' '+insert('NEW')+' '+dirty('OLD')+' '+dirty('NEW')), + ('ad','DELETE',delete('OLD')+' '+dirty('OLD'))]} + + +def optimized_manifest(): + def valid(alias): + tag='j.tag' + whitespace=[chr(n).encode('utf-8').hex() for n in range(0x3001) if chr(n).isspace()] + ends=','.join('0x'+value for value in whitespace) + invalid=(f"JSON_TYPE(JSON_EXTRACT({alias}.tags,CONCAT('$[',j.ordinal-1,']')))!='STRING' " + f'OR CHAR_LENGTH({tag}) NOT BETWEEN 1 AND 255 OR BINARY LEFT({tag},1) IN ({ends}) ' + f'OR BINARY RIGHT({tag},1) IN ({ends}) ' + f"OR REGEXP_LIKE({tag},CONVERT(0x5b002d1f5d USING utf8mb4),'c')") + return (f"IF JSON_TYPE({alias}.tags)!='ARRAY' OR JSON_LENGTH({alias}.tags)>100 OR EXISTS (" + f"SELECT 1 FROM JSON_TABLE({alias}.tags,'$[*]' COLUMNS(ordinal FOR ORDINALITY," + f"tag VARCHAR(1020) CHARACTER SET utf8mb4 PATH '$' ERROR ON ERROR)) j WHERE {invalid}) " + "THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Invalid canonical shared annotation tags'; END IF;") + def insert(alias): + return (valid(alias)+f' INSERT INTO `{lookup_module.SCHEMA}`.`{lookup_module.TABLE}` ({",".join(lookup_module.COLUMNS)}) ' + f'SELECT {alias}.project_uuid,{alias}.target_kind,{alias}.target_uuid,{alias}.profile_uuid,' + f"CAST(j.tag AS BINARY) FROM JSON_TABLE({alias}.tags,'$[*]' " + "COLUMNS(tag VARCHAR(1020) CHARACTER SET utf8mb4 PATH '$' ERROR ON ERROR)) j;") + delete,dirty=lookup_module._delete,lookup_module._dirty + return {lookup_module.PREFIX+suffix:{'table':'shared_annotation','event':event,'timing':'AFTER','body':'BEGIN '+body+' END'} + for suffix,event,body in [('ai','INSERT',insert('NEW')+' '+dirty('NEW')), + ('au','UPDATE',delete('OLD')+' '+insert('NEW')+' '+dirty('OLD')+' '+dirty('NEW')), + ('ad','DELETE',delete('OLD')+' '+dirty('OLD'))]} + + +def run(output): + report={'kind':'same-server-native-sql-trigger-microbenchmark','samples':10,'targets_per_transaction':10, + 'canonical_tags_per_row':6,'includes':'10 canonical UPDATE statements and native transaction commit; no HTTP/event/provenance reads'} + with tempfile.TemporaryDirectory(prefix='rieke-tag-trigger-timing-') as directory: + root=Path(create_project(Path(directory)/'projects','Private tag trigger timing')['path']);raw=None + try: + native.ensure_native_database(root);raw=pymysql.connect(**native.connection_parameters(root),autocommit=True);conn=NativeConnection(raw) + conn.query('CREATE DATABASE recording_workspace') + conn.query('CREATE TABLE recording_workspace.shared_annotation (project_uuid varchar(36),target_kind varchar(8),target_uuid varchar(36),profile_uuid varchar(36),tags JSON NOT NULL,revision INT NOT NULL,PRIMARY KEY(project_uuid,target_kind,target_uuid,profile_uuid)) ENGINE=InnoDB') + conn.query('CREATE TABLE recording_workspace.app_state_generation (project_uuid varchar(36),scope_kind varchar(32),scope_uuid varchar(36),generation BIGINT,PRIMARY KEY(project_uuid,scope_kind,scope_uuid)) ENGINE=InnoDB') + project,profile=str(uuid.uuid4()),str(uuid.uuid4());all_ids=[str(uuid.uuid4()) for _ in range(1500)];ids=all_ids[:10] + conn.query('INSERT INTO recording_workspace.app_state_generation VALUES (%s,%s,%s,0)',(project,'shared_annotations',project)) + for key in all_ids:conn.query('INSERT INTO recording_workspace.shared_annotation VALUES (%s,%s,%s,%s,%s,1)',(project,'epoch',key,profile,json.dumps(['all','bucket:7','ON','é','profile:0','review:0']))) + proof={'project_uuid':project,'tables':{'shared_annotation':{'count':1500,'xor':'0'*64}}} + lookup=lookup_module.bootstrap(conn,project,proof);assert lookup.ready,lookup.reason + import runpy + validation=runpy.run_path(str(Path(__file__).with_name('benchmark_tag_trigger_validation.py'))) + before=validation['optimized_manifest']() + fixed={name:dict(spec) for name,spec in before.items()} + for spec in fixed.values(): + for alias in ('OLD','NEW'): + for field in ('project_uuid','target_kind','target_uuid','profile_uuid'): + spec['body']=spec['body'].replace(field+'='+alias+'.'+field,field+'=CONVERT('+alias+'.'+field+' USING ascii) COLLATE ascii_bin') + manifests={'before':before,'fixed_comparison':fixed} + report['mysql_version']=conn.query('SELECT VERSION()').fetchone()[0] + report['column_collations']=conn.query("SELECT TABLE_NAME,COLUMN_NAME,COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='recording_workspace' AND TABLE_NAME IN ('shared_annotation','app_shared_tag_lookup')",as_dict=True).fetchall() + report['delete_plans']={} + for variant in ('before','fixed_comparison'): + delete=validation['historical_delete']('OLD') + if variant=='fixed_comparison': + for field in ('project_uuid','target_kind','target_uuid','profile_uuid'): + delete=delete.replace(field+'=OLD.'+field,field+'=CONVERT(OLD.'+field+' USING ascii) COLLATE ascii_bin') + for field in ('project_uuid','target_kind','target_uuid','profile_uuid'):delete=delete.replace('OLD.'+field,'p_'+field) + declarations=','.join('IN p_'+field+' VARCHAR(36) CHARACTER SET utf8mb4' for field in ('project_uuid','target_kind','target_uuid','profile_uuid')) + conn.query('CREATE PROCEDURE recording_workspace.plan_'+variant+'('+declarations+') BEGIN EXPLAIN FORMAT=JSON '+delete+' END') + report['delete_plans'][variant]=json.loads(conn.query('CALL recording_workspace.plan_'+variant+'(%s,%s,%s,%s)',(project,'epoch',ids[0],profile)).fetchone()[0]) + + for label,manifest in manifests.items(): + for name,spec in manifest.items(): + conn.query('DROP TRIGGER recording_workspace.'+name) + conn.query('CREATE TRIGGER recording_workspace.'+name+' AFTER '+spec['event']+' ON recording_workspace.shared_annotation FOR EACH ROW '+spec['body']) + report[label]={'manifest_sha256':hashlib.sha256(json.dumps(manifest,sort_keys=True).encode()).hexdigest()} + samples=[] + before_reads=conn.query("SHOW SESSION STATUS WHERE Variable_name='Handler_read_next'").fetchone()[1] + for sample in range(15): + values=json.dumps(['all','bucket:7','ON','é','profile:0','review:'+str(sample%2)]) + started=time.perf_counter() + with conn.transaction: + for key in ids:conn.query('UPDATE recording_workspace.shared_annotation SET tags=%s,revision=revision+1 WHERE project_uuid=%s AND target_kind=%s AND target_uuid=%s AND profile_uuid=%s',(values,project,'epoch',key,profile)) + elapsed=time.perf_counter()-started + if sample>=5:samples.append(elapsed) + report[label]['handler_read_next']=int(conn.query("SHOW SESSION STATUS WHERE Variable_name='Handler_read_next'").fetchone()[1])-int(before_reads) + report[label].update(seconds=samples,median_seconds=statistics.median(samples),p95_seconds=sorted(samples)[9]) + assert lookup.targets('review:1')==set() + Path(output).write_text(json.dumps(report,indent=2)+'\n');print(json.dumps({label:{k:v for k,v in value.items() if k!='seconds'} for label,value in report.items() if isinstance(value,dict)}),flush=True) + finally: + if raw is not None:raw.close() + native.stop_native_database(root) + + +if __name__=='__main__': + import sys + run(sys.argv[1]) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_tag_sequence.py b/docs/dev/scale-audit-2026-09-29/benchmark_tag_sequence.py new file mode 100644 index 0000000..11ebfe7 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_tag_sequence.py @@ -0,0 +1,340 @@ +"""Native tag-ten, tag-another-ten, filter-twenty and hierarchical cell/epoch workflow. + +Every project/database is disposable. Acquisition metadata is synthetic; actual +MySQL, triggers, Flask routes, derived indexes and each version's save hooks +are used. Native SQL commits are checked immediately; any background recovery +mirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude +oracle work, and do not model browser concurrency/rendering. Sequential bundle +times are sums of their separately measured requests. Profiles are separate. +""" +import argparse +import copy +import cProfile +import datetime as dt +import hashlib +import json +import math +import os +from pathlib import Path +import pstats +import resource +import statistics +import sys +import tempfile +import time +import traceback + + +def digest(path):return hashlib.sha256(Path(path).read_bytes()).hexdigest() +def percentiles(values): + ordered=sorted(values) + return {'samples_seconds':values,'p50_seconds':statistics.median(values),'p95_seconds':ordered[math.ceil(.95*len(ordered))-1], + 'p99_seconds':ordered[math.ceil(.99*len(ordered))-1],'maximum_seconds':max(values),'quantile_method':'nearest_rank'} +def rule(tag,scope='effective'):return {'field':'annotations/'+scope+'/tags','operator':'contains','value':tag} +def tags(ordinal,profile,*,cell=False): + if cell:return ['cell-common',f'cell-bucket:{ordinal%5}',f'cell-author:{profile}','Inherited' if profile==0 else 'inherited',f'cell-type:{ordinal%2}'] + return ['all',f'gate:{profile}' if ordinal%(profile+2)==0 else f'rest:{profile}','QC' if ordinal%2==0 else 'qc', + 'é' if ordinal%3==0 else 'e\u0301',f'bucket:{ordinal%17}'] +def source_inventory(root): + return {str(path.relative_to(root)):digest(path) for path in sorted((root/'python').rglob('*.py'))} + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--source-root',type=Path,required=True) + ap.add_argument('--mysql-runtime-root',type=Path,required=True);ap.add_argument('--epochs',type=int,required=True) + ap.add_argument('--samples',type=int,default=5);ap.add_argument('--targets',default='tag10_then10_filter20_and_cell_epoch_hierarchy') + ap.add_argument('--output',type=Path,required=True);ap.add_argument('--profile',action='store_true') + ap.add_argument('--page-cells',action='store_true',default=True) + args=ap.parse_args() + args.output=args.output.resolve();root=args.source_root.resolve(strict=True) + if args.output.exists():ap.error('Choose an unused output receipt') + if args.epochs<200 or args.samples<1:ap.error('Use at least200 epochs and one sample') + # Product and fixture imports must come from the selected immutable tree. + sys.path[:0]=[str(root/'python'),str(root/'docs/dev/scale-audit-2026-09-29')] + os.chdir(root) + from benchmark_service_scale import fixture,Details,uid + import benchmark_service_scale + from recording_workspace import connect,workspace_tables + from workspace_projects import create_project + import workspace_native_mysql as native + from workspace_mysql_runtime import _probe,runtime_spec + from workspace_disk_index import DiskMetadataIndex + from workspace_api import create_app + import workspace_state_snapshot as snapshot + runtime=_probe(args.mysql_runtime_root.resolve(strict=True),runtime_spec(root)[0]['mysql_version']) + def runtime_binary(name='mysqld'): + if name not in {'mysqld','mysql','mysqldump'}:raise ValueError('Unsupported native executable') + return Path(runtime[name]) + native.native_binary=runtime_binary + report={'scope':__doc__,'epochs':args.epochs,'profiles':3,'tags_per_annotation':5,'protocols':2,'samples':args.samples, + 'source_root':str(root),'source_inventory_before':source_inventory(root),'fixture_module':str(Path(benchmark_service_scale.__file__).resolve()), + 'harness_sha256':digest(__file__),'started_at':dt.datetime.now(dt.timezone.utc).isoformat(),'release_ready':False,'operations':{},'checks':[], + 'page_cells':True,'target_specification':args.targets,'baseline_harness_sha256':digest(Path(__file__).with_name('benchmark_scientist_tag_workflow.py'))} + samples={};sql_samples={};app=None;dj=None;project_root=None;index=None;closed=False + def check(name,condition,**detail): + report['checks'].append({'name':name,'passed':bool(condition),**detail}) + if not condition:raise AssertionError(name) + def log(message):print(message,flush=True) + started=time.perf_counter() + try: + with tempfile.TemporaryDirectory(prefix='rieke-tag-sequence-') as directory: + project_root=Path(create_project(Path(directory)/'projects','Disposable scientist tag workflow')['path']) + try: + native.ensure_native_database(project_root);dj=connect({'kind':'native-project'},project_dir=project_root) + service,protocol=fixture(args.epochs);service.project_dir=project_root + service.project=json.loads((project_root/'project.json').read_text());service.config=json.loads((project_root/'catalog.json').read_text());service.dj=dj + service.manifests={item['source_sha256']:{'source_path':'/synthetic/'+item['filename']} for item in service.sources} + other=uid(-3);service.protocols[other]=copy.deepcopy(service.protocols[protocol]) + service.protocols[other]['definition']['protocol_uuid']=other;service.protocols[other]['result']['protocol_uuid']=other + for value in service.protocols.values(): + value['definition']['project_uuid']=service.project['project_uuid'] + value['definition']['query']={'version':1,'all':[{'field':'EpochBlock.protocol_name','operator':'eq','value':'Synthetic'}]} + index=DiskMetadataIndex.build(project_root/'cache'/'metadata.sqlite',service.rows,Details(service.rows),service.sources,'tag-workflow-fixture-v1',service.project['project_uuid']) + service.disk_index=index;service.details=index.details + Project,_,_,_=workspace_tables(dj);project=service.project['project_uuid'] + Project.insert1({'project_uuid':project,'name':service.project['name'],'directory':str(project_root)}) + app=create_app(project_root,root/'.rieke-runtime/retinanalysis',service=service) + assert service._recovery_tracker.ready,service._recovery_tracker.reason + store=app.extensions['curation_store'];shared=app.extensions['shared_annotations'];authors=[uid(-100-i) for i in range(3)] + author_names=['Same Scientist','Same Scientist','Scientist C'];stamp=dt.datetime(2026,9,29,12) + ids=tuple(service.rows);ordinals={identity:i for i,identity in enumerate(ids)};cell_ordinals={identity:i for i,identity in enumerate(service.cells)} + report['mysql_version']=dj.conn().query('SELECT VERSION()').fetchone()[0] + seed=time.perf_counter();log(json.dumps({'stage':'seed','epochs':args.epochs,'source_root':str(root)})) + with dj.conn().transaction: + shared.Profile.insert([{'project_uuid':project,'profile_uuid':author,'display_name':author_names[p],'created_at':stamp,'created_by':'workflow oracle'} for p,author in enumerate(authors)]) + batch=[] + for kind,identities in [('epoch',ids),('cell',tuple(service.cells))]: + for ordinal,identity in enumerate(identities): + for p,author in enumerate(authors): + batch.append({'project_uuid':project,'target_kind':kind,'target_uuid':identity,'profile_uuid':author, + 'tags':tags(ordinal,p,cell=kind=='cell'),'author_name':author_names[p],'revision':1,'updated_at':stamp}) + if len(batch)==500:shared.Annotation.insert(batch);batch=[] + if batch:shared.Annotation.insert(batch);batch=[] + for p,current in enumerate((protocol,other)): + for identity in ids: + batch.append({'project_uuid':project,'protocol_uuid':current,'epoch_uuid':identity,'included':True, + 'tags':[f'dataset:{p}',*[f'dataset-tag:{i}' for i in range(4)]],'review_state':'unreviewed','revision':1, + 'metadata_fingerprint':service._fingerprints[identity]}) + if len(batch)==500:store.Curation.insert(batch);batch=[] + if batch:store.Curation.insert(batch);batch=[] + report['seed_seconds']=time.perf_counter()-seed + checkpoint=time.perf_counter();snapshot.save(project_root,dj.conn(),service=service);report['seed_checkpoint_seconds']=time.perf_counter()-checkpoint + log(json.dumps({'stage':'timed_operations','epochs':args.epochs,'seed_seconds':report['seed_seconds']})) + client=app.test_client();base=f'/api/protocols/{protocol}';headers={'X-Workspace-Request':'1','Origin':'http://localhost:8766'} + + + import inspect + import threading + app_db_lock=inspect.getclosurevars(app.view_functions['annotation_batch_read']).nonlocals['db_lock'] + first=ids[:10];second=ids[100:110];selected=first+second;cell=service.rows[first[0]]['cell_uuid'] + children=tuple(key for key in ids if service.rows[key]['cell_uuid']==cell) + assert len(children)==100 and service.rows[second[0]]['cell_uuid']!=cell + epoch_marker='sequence-selected';cell_marker='sequence-cell' + epoch_predicate={'all':[rule(epoch_marker,'epoch')]} + cell_predicate={'all':[rule(cell_marker,'cell')]} + hierarchy={'all':[rule(cell_marker,'cell'),rule(epoch_marker,'epoch')]} + model={(kind,key,p):set() for kind,keys in [('epoch',selected),('cell',(cell,))] for key in keys for p in range(3)} + revisions={key:1 for key in model} + report['selected_epoch_uuids']={'first10':first,'second10':second,'cell':cell,'cell_children':children} + report['backup_receipts']=[] + def sql_status(): + with app_db_lock:return {key:int(value) for key,value in dj.conn().query("SHOW SESSION STATUS WHERE Variable_name IN ('Bytes_sent','Questions')").fetchall()} + def request(method,path,*,query=None,body=None): + response=client.get(path,query_string=query) if method=='GET' else client.post(path,json=body,headers=headers) + value=response.get_json() + if response.status_code!=200:raise AssertionError((method,path,response.status_code,value)) + return value + def measure(name,callback): + before=sql_status();began=time.perf_counter();value=callback();elapsed=time.perf_counter()-began;after=sql_status() + samples.setdefault(name,[]).append(elapsed);sql_samples.setdefault(name,[]).append({key:after[key]-before[key] for key in before}) + return value,elapsed + def wanted_tags(kind,key,p): + ordinal=ordinals[key] if kind=='epoch' else cell_ordinals[key] + return sorted([*tags(ordinal,p,cell=kind=='cell'),*model.get((kind,key,p),())]) + def validate_target(row,kind,key): + assert row['target_uuid']==key and row['target_kind']==kind + assert row['revisions']=={author:revisions.get((kind,key,p),1) for p,author in enumerate(authors)} + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['tags'])==sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,key,p)) + def preflight(label,keys,p,*,timed=True): + call=lambda:request('POST','/api/annotations/read',body={'target_kind':'epoch','target_uuids':list(keys)}) + value,_=measure(label,call) if timed else (call(),0) + assert set(value['targets'])==set(keys) + for key,row in value['targets'].items():validate_target(row,'epoch',key) + return {key:value['targets'][key]['revisions'][authors[p]] for key in keys} + def change(label,kind,keys,p,marker,add,expected=None,*,timed=True): + body={'target_kind':kind,'target_uuids':list(keys),'profile_uuid':authors[p], + 'tags_add':[marker] if add else [],'tags_remove':[] if add else [marker], + 'expected_revisions':expected or {key:revisions[(kind,key,p)] for key in keys}} + call=lambda:request('POST','/api/annotations',body=body) + value,_=measure(label,call) if timed else (call(),0) + assert value['changed']==len(keys) + if 'persistence' in value: + assert value['persistence']['database']=='committed',value + report['backup_receipts'].append({'operation':label,'persistence':value['persistence']}) + for key in keys: + revisions[(kind,key,p)]+=1 + if add:model[(kind,key,p)].add(marker) + else:model[(kind,key,p)].remove(marker) + assert set(value['targets'])==set(keys) + for key,row in value['targets'].items():validate_target(row,kind,key) + # The oracle uses the application's actual SQL lock so the + # candidate's background mirror cannot race this connection. + with app_db_lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':kind,'profile_uuid':authors[p]}&[{'target_uuid':key} for key in keys]).to_dicts() + assert {row['target_uuid'] for row in rows}==set(keys) + for row in rows: + key=row['target_uuid'];assert row['revision']==revisions[(kind,key,p)] and sorted(row['tags'])==wanted_tags(kind,key,p) + return value + def query(predicate,**extra):return {'tag_predicate':json.dumps(predicate,separators=(',',':')),**extra} + def page(label,predicate,wanted,*,offset=0,timed=True): + call=lambda:request('GET',base+'/epochs',query=query(predicate,limit=60,offset=offset,include_cells='true')) + value,elapsed=measure(label,call) if timed else (call(),0) + assert value['total']==len(wanted) + assert tuple(row['epoch_uuid'] for row in value['epochs'])==wanted[offset:offset+60] + counts={} + for key in wanted: + target_cell=service.rows[key]['cell_uuid'];counts[target_cell]=counts.get(target_cell,0)+1 + assert {row['cell_uuid']:row['epochs'] for row in value['cells']}==counts + for row in value['epochs']: + key=row['epoch_uuid'];target_cell=service.rows[key]['cell_uuid'] + for kind,field,target in [('epoch','epoch_tags',key),('cell','cell_tags',target_cell)]: + assert sorted((chip['tag'],chip['profile_uuid']) for chip in row['annotations'][field])==sorted((tag,author) for p,author in enumerate(authors) for tag in wanted_tags(kind,target,p)) + assert row['curation']['revision']==1 + assert sorted(row['curation']['tags'])==sorted(['dataset:0',*[f'dataset-tag:{j}' for j in range(4)]]) + with app_db_lock: + exact,_=service._epoch_page_identities(protocol,query(predicate));assert tuple(exact)==wanted + return value,elapsed + def child_sql(): + with app_db_lock: + rows=(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'}&[{'target_uuid':key} for key in children]).to_dicts() + return sorted((row['target_uuid'],row['profile_uuid'],row['revision'],tuple(sorted(row['tags'])),row['author_name'],str(row['updated_at'])) for row in rows) + # Index construction belongs to preparation, outside all action + # distributions. Record it separately instead of hiding its cost. + prepared=time.perf_counter() + import importlib.util + prepare_project_annotations=None + if importlib.util.find_spec('workspace_annotation_preparation') is not None: + from workspace_annotation_preparation import prepare_project_annotations + with app_db_lock: + report['project_annotation_preparation']=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader')) + assert report['project_annotation_preparation']['status']=='ready',report['project_annotation_preparation'] + page('preparation_epoch_filter',epoch_predicate,()) + page('preparation_cell_filter',cell_predicate,()) + page('preparation_hierarchical_filter',hierarchy,()) + report['preparation_index_seconds']=time.perf_counter()-prepared + check('preparation_exact_empty_memberships',True) + report['bundle_definitions']={ + 'tag10_then10_filter20_http_total':['first10_revision_preflight','first10_save','second10_revision_preflight','second10_save','filter20'], + 'cell_tag_then_cell_filter_http_total':['cell_save','filter_cell100'], + 'first10_selected_action_http_total':['first10_revision_preflight','first10_save'], + 'second10_selected_action_http_total':['second10_revision_preflight','second10_save']} + for iteration in range(args.samples): + p=iteration%3 + expected=preflight('first10_revision_preflight',first,p) + change('first10_save','epoch',first,p,epoch_marker,True,expected) + expected=preflight('second10_revision_preflight',second,p) + change('second10_save','epoch',second,p,epoch_marker,True,expected) + value,_=page('filter20',epoch_predicate,selected) + before_children=child_sql() + # The rendered page already carries cell revisions, as the + # direct-cell editor does; no selected-epoch preflight. + cell_expected={cell:value['epochs'][0]['annotations']['revisions']['cell'][authors[p]]} + change('cell_save','cell',(cell,),p,cell_marker,True,cell_expected) + page('filter_cell100',cell_predicate,children) + page('filter_cell100_last_page',cell_predicate,children,offset=40,timed=False) + page('filter_cell_and_epoch10',hierarchy,first) + page('oracle_cell_marker_not_direct',{'all':[rule(cell_marker,'epoch')]},(),timed=False) + assert child_sql()==before_children,'Cell add changed child annotation records' + expected=preflight('remove_first10_revision_preflight',first,p) + change('remove_first10_save','epoch',first,p,epoch_marker,False,expected) + page('filter_hierarchy_after_epoch_remove',hierarchy,()) + page('filter_remaining10',epoch_predicate,second) + expected=preflight('remove_second10_revision_preflight',second,p) + change('remove_second10_save','epoch',second,p,epoch_marker,False,expected) + page('filter_after_all_epoch_removals',epoch_predicate,()) + before_children=child_sql() + change('remove_cell_save','cell',(cell,),p,cell_marker,False) + page('filter_after_cell_removal',cell_predicate,()) + assert child_sql()==before_children,'Cell removal changed child annotation records' + with app_db_lock:assert len(shared.Annotation&{'project_uuid':project,'target_kind':'epoch'})==args.epochs*3 + for label,parts in report['bundle_definitions'].items():samples.setdefault(label,[]).append(sum(samples[part][-1] for part in parts)) + log(json.dumps({'stage':'sequence_cycle','epochs':args.epochs,'iteration':iteration+1})) + def flush_backup(): + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush();report['final_backup_status']=scheduler.status() + if args.profile: + for name,keys in [('first10',first),('second10',second)]: + expected=preflight('profile_'+name+'_preflight',keys,0,timed=False) + change('profile_'+name+'_save','epoch',keys,0,epoch_marker,True,expected,timed=False) + flush_backup() + import re + connection=dj.conn();original_query=connection.query;owner=threading.get_ident();sql_calls=[] + def traced_query(statement,*positional,**keywords): + began=time.perf_counter() + try:return original_query(statement,*positional,**keywords) + finally:sql_calls.append({'thread':'filter' if threading.get_ident()==owner else 'background','sql_shape':re.sub(r"'[^']*'","'?'",str(statement))[:240],'seconds':time.perf_counter()-began}) + profiler=cProfile.Profile();connection.query=traced_query + try:profiled=profiler.runcall(lambda:request('GET',base+'/epochs',query=query(epoch_predicate,limit=60,offset=0,include_cells='true'))) + finally:connection.query=original_query + assert profiled['total']==20 and tuple(row['epoch_uuid'] for row in profiled['epochs'])==selected + stats=pstats.Stats(profiler);rows=[] + for key,value in sorted(stats.stats.items(),key=lambda item:item[1][3],reverse=True): + path=Path(key[0]);rows.append({'file':str(path.relative_to(root)) if path.is_absolute() and path.is_relative_to(root) else key[0], + 'line':key[1],'function':key[2],'primitive_calls':value[0],'calls':value[1],'self_seconds':value[2],'cumulative_seconds':value[3]}) + report['filter20_cpu_profile']={'top_functions':rows[:100],'native_sql_calls':sql_calls,'limits':'Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap.'} + page('profile_filter20_verify',epoch_predicate,selected,timed=False) + if prepare_project_annotations is not None: + flush_backup();began=time.perf_counter() + with app_db_lock: + checkpoint=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader')) + assert checkpoint['status']=='ready' and checkpoint['checkpoint']['saved'],checkpoint + previous_builds=shared._shared_tag_index.stats['full_builds'] + shared._shared_tag_index.close() + reopened=prepare_project_annotations(service,store,shared,protocol_state=app.extensions.get('protocol_state_reader'),reuse=True) + assert reopened['status']=='ready' and reopened['checkpoint_restore']['restored'],reopened + after_builds=shared._shared_tag_index.stats['full_builds'] + assert after_builds in (0,previous_builds),(previous_builds,after_builds) + report['same_server_checkpoint_reopen']={'seconds':time.perf_counter()-began,'checkpoint':checkpoint,'reopened':reopened,'full_builds_before':previous_builds,'full_builds_after':after_builds,'scope':'Shared derived index closed and reopened within the same native server; not a native process restart.'} + page('same_server_reopened_filter20',epoch_predicate,selected) + check('same_server_checkpoint_restores_exact_twenty_without_rebuild',True) + for name,keys in [('first10',first),('second10',second)]: + change('profile_remove_'+name,'epoch',keys,0,epoch_marker,False,timed=False) + flush_backup() + check('canonical_final_markers_removed',not any(model.values())) + report['workflow_peak_rss_before_durable_oracle_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + began=time.perf_counter();state=snapshot.load(project_root/'app-state.json');report['durable_snapshot_verify_seconds']=time.perf_counter()-began + saved={(row['target_kind'],row['target_uuid'],row['profile_uuid']):row for row in state['tables']['shared_annotation']} + for (kind,key,p),revision in revisions.items(): + row=saved[(kind,key,authors[p])];assert row['revision']==revision and sorted(row['tags'])==wanted_tags(kind,key,p) + check('flushed_recovery_mirror_exact_revisions_and_removal',True,records=len(revisions)) + check('one_canonical_cell_record_no_child_copies',sum(row['target_kind']=='epoch' for row in saved.values())==args.epochs*3,child_epochs=len(children)) + check('independent_protocol_curation_untouched',len(state['tables']['curation'])==args.epochs*2 and all(row['revision']==1 for row in state['tables']['curation'])) + loaded={name:str(Path(module.__file__).resolve()) for name,module in sys.modules.items() if (name.startswith('workspace_') or name=='recording_workspace') and getattr(module,'__file__',None)} + check('all_product_modules_loaded_from_selected_source',all(Path(path).is_relative_to(root) for path in loaded.values()));report['loaded_product_modules']=loaded + finally: + if app is not None: + scheduler=app.extensions.get('backup_scheduler') + if scheduler is not None: + scheduler.flush() + close=getattr(scheduler,'close',None) + if close is not None:close(flush=False) + shared=app.extensions.get('shared_annotations');derived=getattr(shared,'_shared_tag_index',None) + if derived is not None:derived.close() + lock=app.extensions.get('app_state_session_lock') + if lock is not None:lock.close() + if index is not None:index.close() + if dj is not None:dj.conn().close() + if project_root is not None:closed=native.stop_native_database(project_root) + report['owned_native_runtime_stopped']=closed + except Exception as error: + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};log(traceback.format_exc()) + report['operations']={name:{**percentiles(values),'sql_session_deltas':sql_samples.get(name,[])} for name,values in samples.items()} + report['source_inventory_after']=source_inventory(root);report['source_unchanged']=report['source_inventory_before']==report['source_inventory_after'] + report['harness_unchanged']=digest(__file__)==report['harness_sha256'] + report['seconds']=time.perf_counter()-started;report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat();report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['passed']=not report.get('error') and closed and report['source_unchanged'] and report['harness_unchanged'] and all(item['passed'] for item in report['checks']) + args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n');log(json.dumps({'stage':'done','epochs':args.epochs,'passed':report['passed'],'seconds':report['seconds'],'output':str(args.output)})) + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_tag_trigger_validation.py b/docs/dev/scale-audit-2026-09-29/benchmark_tag_trigger_validation.py new file mode 100644 index 0000000..928d291 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_tag_trigger_validation.py @@ -0,0 +1,110 @@ +"""Disposable same-server old/new trigger validation timing; no UI timing claim.""" +import hashlib,json,statistics,tempfile,time,uuid +from pathlib import Path +import pymysql +from test_workspace_state_generation import NativeConnection +import workspace_native_tag_lookup as lookup_module +from workspace_projects import create_project +import workspace_native_mysql as native + + +def historical_delete(alias): + return (f'DELETE FROM `{lookup_module.SCHEMA}`.`{lookup_module.TABLE}` WHERE project_uuid={alias}.project_uuid ' + f'AND target_kind={alias}.target_kind AND target_uuid={alias}.target_uuid ' + f'AND profile_uuid={alias}.profile_uuid;') + + +def historical_dirty(alias): + return f'UPDATE `{lookup_module.SCHEMA}`.`{lookup_module.MARKER}` SET dirty=1 WHERE project_uuid={alias}.project_uuid;' + + +def baseline_manifest(): + def valid(alias): + tag=lookup_module._tag(alias) + whitespace=[chr(n).encode('utf-8').hex() for n in range(0x3001) if chr(n).isspace()] + ends=','.join('0x'+value for value in whitespace) + controls=' OR '.join(f'LOCATE(CHAR({n}),{tag})>0' for n in range(32)) + invalid=(f"JSON_TYPE(JSON_EXTRACT({alias}.tags,CONCAT('$[',j.ordinal-1,']')))!='STRING' " + f'OR CHAR_LENGTH({tag}) NOT BETWEEN 1 AND 255 OR BINARY LEFT({tag},1) IN ({ends}) ' + f'OR BINARY RIGHT({tag},1) IN ({ends}) OR {controls}') + return (f"IF JSON_TYPE({alias}.tags)!='ARRAY' OR JSON_LENGTH({alias}.tags)>100 OR EXISTS (" + f"SELECT 1 FROM JSON_TABLE({alias}.tags,'$[*]' COLUMNS(ordinal FOR ORDINALITY)) j WHERE {invalid}) " + "THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Invalid canonical shared annotation tags'; END IF;") + def insert(alias): + return (valid(alias)+f' INSERT INTO `{lookup_module.SCHEMA}`.`{lookup_module.TABLE}` ({",".join(lookup_module.COLUMNS)}) ' + f'SELECT {alias}.project_uuid,{alias}.target_kind,{alias}.target_uuid,{alias}.profile_uuid,' + f"CAST({lookup_module._tag(alias)} AS BINARY) FROM JSON_TABLE({alias}.tags,'$[*]' " + "COLUMNS(ordinal FOR ORDINALITY)) j;") + delete,dirty=historical_delete,historical_dirty + return {lookup_module.PREFIX+suffix:{'table':'shared_annotation','event':event,'timing':'AFTER','body':'BEGIN '+body+' END'} + for suffix,event,body in [('ai','INSERT',insert('NEW')+' '+dirty('NEW')), + ('au','UPDATE',delete('OLD')+' '+insert('NEW')+' '+dirty('OLD')+' '+dirty('NEW')), + ('ad','DELETE',delete('OLD')+' '+dirty('OLD'))]} + + +def optimized_manifest(): + def valid(alias): + tag='j.tag' + whitespace=[chr(n).encode('utf-8').hex() for n in range(0x3001) if chr(n).isspace()] + ends=','.join('0x'+value for value in whitespace) + invalid=(f"JSON_TYPE(JSON_EXTRACT({alias}.tags,CONCAT('$[',j.ordinal-1,']')))!='STRING' " + f'OR CHAR_LENGTH({tag}) NOT BETWEEN 1 AND 255 OR BINARY LEFT({tag},1) IN ({ends}) ' + f'OR BINARY RIGHT({tag},1) IN ({ends}) ' + f"OR REGEXP_LIKE({tag},CONVERT(0x5b002d1f5d USING utf8mb4),'c')") + return (f"IF JSON_TYPE({alias}.tags)!='ARRAY' OR JSON_LENGTH({alias}.tags)>100 OR EXISTS (" + f"SELECT 1 FROM JSON_TABLE({alias}.tags,'$[*]' COLUMNS(ordinal FOR ORDINALITY," + f"tag VARCHAR(1020) CHARACTER SET utf8mb4 PATH '$' ERROR ON ERROR)) j WHERE {invalid}) " + "THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Invalid canonical shared annotation tags'; END IF;") + def insert(alias): + return (valid(alias)+f' INSERT INTO `{lookup_module.SCHEMA}`.`{lookup_module.TABLE}` ({",".join(lookup_module.COLUMNS)}) ' + f'SELECT {alias}.project_uuid,{alias}.target_kind,{alias}.target_uuid,{alias}.profile_uuid,' + f"CAST(j.tag AS BINARY) FROM JSON_TABLE({alias}.tags,'$[*]' " + "COLUMNS(tag VARCHAR(1020) CHARACTER SET utf8mb4 PATH '$' ERROR ON ERROR)) j;") + delete,dirty=historical_delete,historical_dirty + return {lookup_module.PREFIX+suffix:{'table':'shared_annotation','event':event,'timing':'AFTER','body':'BEGIN '+body+' END'} + for suffix,event,body in [('ai','INSERT',insert('NEW')+' '+dirty('NEW')), + ('au','UPDATE',delete('OLD')+' '+insert('NEW')+' '+dirty('OLD')+' '+dirty('NEW')), + ('ad','DELETE',delete('OLD')+' '+dirty('OLD'))]} + + +def run(output): + report={'kind':'same-server-native-sql-trigger-microbenchmark','samples':50,'targets_per_transaction':10, + 'canonical_tags_per_row':6,'includes':'10 canonical UPDATE statements and native transaction commit; no HTTP/event/provenance reads'} + with tempfile.TemporaryDirectory(prefix='rieke-tag-trigger-timing-') as directory: + root=Path(create_project(Path(directory)/'projects','Private tag trigger timing')['path']);raw=None + try: + native.ensure_native_database(root);raw=pymysql.connect(**native.connection_parameters(root),autocommit=True);conn=NativeConnection(raw) + conn.query('CREATE DATABASE recording_workspace') + conn.query('CREATE TABLE recording_workspace.shared_annotation (project_uuid varchar(36),target_kind varchar(8),target_uuid varchar(36),profile_uuid varchar(36),tags JSON NOT NULL,revision INT NOT NULL,PRIMARY KEY(project_uuid,target_kind,target_uuid,profile_uuid)) ENGINE=InnoDB') + conn.query('CREATE TABLE recording_workspace.app_state_generation (project_uuid varchar(36),scope_kind varchar(32),scope_uuid varchar(36),generation BIGINT,PRIMARY KEY(project_uuid,scope_kind,scope_uuid)) ENGINE=InnoDB') + project,profile=str(uuid.uuid4()),str(uuid.uuid4());ids=[str(uuid.uuid4()) for _ in range(10)] + conn.query('INSERT INTO recording_workspace.app_state_generation VALUES (%s,%s,%s,0)',(project,'shared_annotations',project)) + for key in ids:conn.query('INSERT INTO recording_workspace.shared_annotation VALUES (%s,%s,%s,%s,%s,1)',(project,'epoch',key,profile,json.dumps(['all','bucket:7','ON','é','profile:0','review:0']))) + proof={'project_uuid':project,'tables':{'shared_annotation':{'count':10,'xor':'0'*64}}} + lookup=lookup_module.bootstrap(conn,project,proof);assert lookup.ready,lookup.reason + manifests={'before':baseline_manifest(),'optimized':optimized_manifest()} + report['mysql_version']=conn.query('SELECT VERSION()').fetchone()[0] + for label,manifest in manifests.items(): + for name,spec in manifest.items(): + conn.query('DROP TRIGGER recording_workspace.'+name) + conn.query('CREATE TRIGGER recording_workspace.'+name+' AFTER '+spec['event']+' ON recording_workspace.shared_annotation FOR EACH ROW '+spec['body']) + report[label]={'manifest_sha256':hashlib.sha256(json.dumps(manifest,sort_keys=True).encode()).hexdigest()} + samples=[] + for sample in range(55): + values=json.dumps(['all','bucket:7','ON','é','profile:0','review:'+str(sample%2)]) + started=time.perf_counter() + with conn.transaction: + for key in ids:conn.query('UPDATE recording_workspace.shared_annotation SET tags=%s,revision=revision+1 WHERE project_uuid=%s AND target_kind=%s AND target_uuid=%s AND profile_uuid=%s',(values,project,'epoch',key,profile)) + elapsed=time.perf_counter()-started + if sample>=5:samples.append(elapsed) + report[label].update(seconds=samples,median_seconds=statistics.median(samples),p95_seconds=sorted(samples)[47]) + assert lookup.targets('review:0')=={('epoch',key) for key in ids} + Path(output).write_text(json.dumps(report,indent=2)+'\n');print(json.dumps({label:{k:v for k,v in value.items() if k!='seconds'} for label,value in report.items() if isinstance(value,dict)}),flush=True) + finally: + if raw is not None:raw.close() + native.stop_native_database(root) + + +if __name__=='__main__': + import sys + run(sys.argv[1]) diff --git a/docs/dev/scale-audit-2026-09-29/benchmark_trace_integrity.py b/docs/dev/scale-audit-2026-09-29/benchmark_trace_integrity.py new file mode 100644 index 0000000..fdbc4b8 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/benchmark_trace_integrity.py @@ -0,0 +1,70 @@ +"""Measure fresh-process integrity verification versus bounded trace reading. + +Temporary real H5 payloads, 32 and 256 MiB; file caches are warm after writing. +This is not a cold-disk or tens-of-GB production benchmark. +""" +import hashlib +import json +from pathlib import Path +import statistics +import tempfile +import time +import uuid +from unittest.mock import patch +import h5py +import numpy as np +import workspace_service as module +from recording_workspace import digest +from workspace_service import WorkspaceService + + +def run(size_mib): + with tempfile.TemporaryDirectory(prefix='rieke-trace-integrity-') as directory: + path=Path(directory)/'synthetic.h5' + epoch,stream_id=str(uuid.uuid4()),str(uuid.uuid4()) + with h5py.File(path,'w') as file: + group=file.create_group('/epochs/'+epoch+'/responses/'+stream_id) + group.attrs['uuid']=stream_id;group.attrs['sampleRate']=10000. + group.parent.parent.attrs['uuid']=epoch + values=np.zeros(200000,dtype=[('quantity','f8'),('units','S8')]) + values['quantity']=np.arange(len(values));values['units']=b'pA' + group.create_dataset('data',data=values) + # Actually allocate the payload; no sparse-file timing shortcut. + padding=file.create_dataset('fixture_payload',(size_mib*1024*1024,),dtype='u1') + chunk=np.random.default_rng(7).integers(0,256,1024*1024,dtype='u1') + for offset in range(0,len(padding),len(chunk)):padding[offset:offset+len(chunk)]=chunk + sha=digest(path) + service=WorkspaceService.__new__(WorkspaceService) + service._loaded=True;service._source_signatures={} + service.rows={epoch:{'epoch_uuid':epoch,'source_sha256':sha,'streams':[ + {'uuid':stream_id,'kind':'responses','h5_path':group.name or '/epochs/'+epoch+'/responses/'+stream_id, + 'sample_rate':10000.,'sample_count':len(values),'units':'pA'}]}} + service.manifests={sha:{'source_path':str(path),'source_sha256':sha,'source_size':path.stat().st_size}} + def measured(): + started=time.perf_counter();result=service.trace(epoch,stream_id,start=400,count=20000) + elapsed=time.perf_counter()-started + assert result['values']==list(range(400,20400)) + return elapsed + with patch.object(module,'digest',wraps=digest) as checked: + first=measured();cold_checks=checked.call_count + warm=[measured() for _ in range(5)];warm_checks=checked.call_count-cold_checks + # A same-size content mutation must invalidate the signature and fail. + with h5py.File(path,'a') as file:file['fixture_payload'][0]=int(file['fixture_payload'][0])^1 + try:service.trace(epoch,stream_id,count=1) + except ValueError as error:mutation_result=str(error) + else:raise AssertionError('Changed source must be rejected') + return {'fixture_payload_mib':size_mib,'file_bytes':path.stat().st_size, + 'first_uncached_integrity_trace_seconds':first,'warm_trace_seconds':warm, + 'warm_median_seconds':statistics.median(warm),'first_full_hash_calls':cold_checks, + 'warm_full_hash_calls':warm_checks,'samples_per_window':20000, + 'same_size_mutation_rejected':mutation_result, + 'limits':'Real temp H5; OS page cache warm after construction; no API/HTTP/browser. Not a cold-disk benchmark.'} + + +if __name__=='__main__': + import argparse + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--output',type=Path,required=True) + args=parser.parse_args() + results=[run(size) for size in (32,256)] + args.output.write_text(json.dumps(results,indent=2));print(json.dumps(results,indent=2)) diff --git a/docs/dev/scale-audit-2026-09-29/catalog_collision_scale_probe.py b/docs/dev/scale-audit-2026-09-29/catalog_collision_scale_probe.py new file mode 100644 index 0000000..9ddc9dd --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/catalog_collision_scale_probe.py @@ -0,0 +1,178 @@ +"""Disposable native MySQL collision-lookup plan, timing and transaction proof. + +Never accepts an existing project or connection. No acquisition schema is altered; +all benchmark data lives in throwaway probe tables in a fresh temporary project. +""" +import argparse +import hashlib +import json +from pathlib import Path +import re +import statistics +import tempfile +import time +import traceback +from types import SimpleNamespace + +from workspace_projects import create_project +from workspace_native_mysql import ensure_native_database, stop_native_database, connection_parameters +from recording_workspace import connect,assert_new_catalog_identities + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--output',type=Path,required=True) + parser.add_argument('--epochs',type=int,default=100000) + parser.add_argument('--baseline-batches',type=int,default=5) + args=parser.parse_args() + if args.output.exists():parser.error('Use a fresh output file') + if not 1000<=args.epochs<=1000000:parser.error('epochs must be 1000–1000000') + if not 1<=args.baseline_batches<=100:parser.error('baseline-batches must be 1–100') + temporary=Path(tempfile.mkdtemp(prefix='rieke-collision-scale-')) + report={'epochs':args.epochs,'database_scope':'fresh disposable native MySQL only', + 'probe_sha256':hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + 'limitations':['Lookup benchmark only; not full parser/population/import latency.', + 'Baseline full100k time is extrapolated from measured disjoint200-identity batches; not an observed full baseline run.', + 'This proves the proposed scratch-table algorithm, not product integration.']} + project=dj=None;clean=False + try: + project=Path(create_project(temporary/'projects','Disposable collision probe')['path']) + ensure_native_database(project);dj=connect({'kind':'native-project'},project_dir=project) + from retinanalysis.config import schema as catalog + conn=catalog.schema.connection + report['mysql_version']=conn.query('SELECT VERSION()').fetchone()[0] + report['catalog_columns']={};report['catalog_indexes']={} + for kind in ('Animal','Preparation','Cell','EpochGroup','EpochBlock','Epoch','Response','Stimulus'): + table=getattr(catalog,kind) + report['catalog_columns'][kind]=conn.query(f'SHOW FULL COLUMNS FROM {table.full_table_name} WHERE Field=%s',('h5_uuid',),as_dict=True).fetchone() + report['catalog_indexes'][kind]=conn.query(f'SHOW INDEX FROM {table.full_table_name}',as_dict=True).fetchall() + collation=report['catalog_columns']['Epoch']['Collation'];charset=collation.split('_',1)[0] + assert re.fullmatch(r'[A-Za-z0-9_]+',collation) + conn.query(f'CREATE TABLE `schema`.`identity_scan_probe` (id BIGINT PRIMARY KEY AUTO_INCREMENT,h5_uuid VARCHAR(255) CHARACTER SET {charset} COLLATE {collation} NOT NULL) ENGINE=InnoDB') + # Candidate index is declared before starting the import transaction. + conn.query(f'CREATE TEMPORARY TABLE `schema`.`identity_candidates_probe` (h5_uuid VARCHAR(255) CHARACTER SET {charset} COLLATE {collation} NOT NULL, KEY candidate_uuid(h5_uuid)) ENGINE=InnoDB') + conn.query('CREATE TABLE `schema`.`identity_rollback_probe` (id INT PRIMARY KEY) ENGINE=InnoDB') + def insert(table,values,batch=1000): + for offset in range(0,len(values),batch): + block=values[offset:offset+batch] + conn.query(f'INSERT INTO {table} (h5_uuid) VALUES '+','.join(['(%s)']*len(block)),tuple(block)) + incoming=[f'incoming-{n:09d}' for n in range(args.epochs)] + with conn.transaction:insert('`schema`.`identity_scan_probe`',[f'catalog-{n:09d}' for n in range(args.epochs)]) + baseline='SELECT h5_uuid FROM `schema`.`identity_scan_probe` WHERE '+' OR '.join(['h5_uuid=%s']*200)+' LIMIT 1' + candidate='SELECT existing.h5_uuid FROM `schema`.`identity_scan_probe` AS existing STRAIGHT_JOIN `schema`.`identity_candidates_probe` AS incoming FORCE INDEX(candidate_uuid) ON incoming.h5_uuid=existing.h5_uuid LIMIT 1' + report['baseline_explain']=conn.query('EXPLAIN FORMAT=JSON '+baseline,tuple(incoming[:200])).fetchone()[0] + samples=[] + for n in range(args.baseline_batches): + block=incoming[n*200:n*200+200] + if len(block)!=200:break + start=time.perf_counter();assert conn.query(baseline,tuple(block)).fetchone() is None;samples.append(time.perf_counter()-start) + report['baseline']={'batch_size':200,'measured_batches':len(samples),'samples_seconds':samples,'median_batch_seconds':statistics.median(samples), + 'full_batches_required':(len(incoming)+199)//200,'extrapolated_total_seconds':statistics.median(samples)*((len(incoming)+199)//200)} + assert conn.query("SELECT GET_LOCK('recording_workspace_import',30)").fetchone()[0]==1 + start=time.perf_counter() + with conn.transaction: + insert('`schema`.`identity_candidates_probe`',incoming) + report['candidate_staging_seconds']=time.perf_counter()-start + report['candidate_explain']=conn.query('EXPLAIN FORMAT=JSON '+candidate).fetchone()[0] + report['candidate_analyze']=conn.query('EXPLAIN ANALYZE '+candidate).fetchone()[0] + samples=[] + for _ in range(3): + at=time.perf_counter();assert conn.query(candidate).fetchone() is None;samples.append(time.perf_counter()-at) + report['candidate_lookup']={'samples_seconds':samples,'median_seconds':statistics.median(samples)} + report['candidate_stage_plus_median_seconds']=report['candidate_staging_seconds']+report['candidate_lookup']['median_seconds'] + # A second connection cannot access this connection's scratch table. + import pymysql + other=pymysql.connect(**connection_parameters(project)) + try: + try: + with other.cursor() as cursor:cursor.execute('SELECT COUNT(*) FROM `schema`.`identity_candidates_probe`') + except pymysql.err.ProgrammingError as error:report['connection_local']=error.args[0]==1146 + else:report['connection_local']=False + finally:other.close() + report['collation_cases']=[] + for index,name in enumerate(dict.fromkeys([collation,'utf8mb4_bin','utf8mb4_unicode_ci','utf8mb4_0900_ai_ci'])): + case_charset=name.split('_',1)[0] + source=f'`schema`.`identity_collation_{index}`';temp=f'`schema`.`identity_temp_{index}`' + conn.query(f'CREATE TABLE {source} (h5_uuid VARCHAR(255) CHARACTER SET {case_charset} COLLATE {name} NOT NULL) ENGINE=InnoDB') + conn.query(f'CREATE TEMPORARY TABLE {temp} (h5_uuid VARCHAR(255) CHARACTER SET {case_charset} COLLATE {name} NOT NULL,KEY candidate_uuid(h5_uuid)) ENGINE=InnoDB') + for stored,value in [('ABC','abc'),('résumé','resume'),('trail','trail '),("quote'\\value","quote'\\value"),('plain','other')]: + with conn.transaction: + conn.query(f'DELETE FROM {source}');conn.query(f'DELETE FROM {temp}') + insert(source,[stored]);insert(temp,[value]) + original=conn.query(f'SELECT h5_uuid FROM {source} WHERE h5_uuid=%s LIMIT1'.replace('LIMIT1','LIMIT 1'),(value,)).fetchone() + joined=conn.query(f'SELECT existing.h5_uuid FROM {source} existing STRAIGHT_JOIN {temp} incoming FORCE INDEX(candidate_uuid) ON incoming.h5_uuid=existing.h5_uuid LIMIT 1').fetchone() + report['collation_cases'].append({'collation':name,'stored':stored,'incoming':value,'original':original,'candidate':joined,'equal':original==joined}) + conn.query(f'DROP TEMPORARY TABLE {temp}') + # Lookup/staging cannot commit a preceding write when later work fails. + class RollbackProbe(Exception):pass + try: + with conn.transaction: + conn.query('INSERT INTO `schema`.`identity_rollback_probe` VALUES (1)') + conn.query('DELETE FROM `schema`.`identity_candidates_probe`') + insert('`schema`.`identity_candidates_probe`',[f'catalog-{args.epochs-1:09d}']) + assert conn.query(candidate).fetchone() is not None + raise RollbackProbe() + except RollbackProbe:pass + report['transaction_rollback_preserved']=conn.query('SELECT COUNT(*) FROM `schema`.`identity_rollback_probe`').fetchone()[0]==0 + report['candidate_insert_rollback_preserved']=conn.query('SELECT COUNT(*) FROM `schema`.`identity_candidates_probe`').fetchone()[0]==args.epochs + report['source_row_count_preserved']=conn.query('SELECT COUNT(*) FROM `schema`.`identity_scan_probe`').fetchone()[0]==args.epochs + report['advisory_lock_still_owned']=conn.query("SELECT IS_USED_LOCK('recording_workspace_import')=CONNECTION_ID()").fetchone()[0]==1 + # Exercise the production helper, including its real table metadata, + # ownership checks and bounded parameter batches, in this same fixture. + from workspace_catalog_collision import CatalogCollisionLookup,KINDS + import workspace_catalog_collision as helper_module + report['helper_sha256']=hashlib.sha256(Path(helper_module.__file__).read_bytes()).hexdigest() + relation=dj.FreeTable(conn,'`schema`.`identity_scan_probe`') + probe_catalog=SimpleNamespace(schema=SimpleNamespace(connection=conn),**{kind:relation for kind in KINDS}) + with CatalogCollisionLookup(probe_catalog) as lookup: + report['helper_temp_tables']=len(lookup.temporary) + try: + with conn.transaction: + conn.query('INSERT INTO `schema`.`identity_rollback_probe` VALUES (2)') + at=time.perf_counter() + assert lookup.first_collision('Epoch',incoming) is None + report['helper_100000_lookup_seconds']=time.perf_counter()-at + expected=f'catalog-{args.epochs-1:09d}' + assert lookup.first_collision('Epoch',[*incoming,expected])==expected + raise RollbackProbe() + except RollbackProbe:pass + report['helper_rollback_preserved']=conn.query('SELECT COUNT(*) FROM `schema`.`identity_rollback_probe`').fetchone()[0]==0 + source={'animals':[{'uuid':'incoming-animal','preparations':[{'uuid':'incoming-preparation','cells':[ + {'uuid':'incoming-cell','epoch_groups':[{'uuid':'incoming-group','epoch_blocks':[ + {'uuid':'incoming-block','epochs':[{'uuid':key} for key in incoming]}]}]}]}]}]} + with conn.transaction: + at=time.perf_counter();assert_new_catalog_identities(source,probe_catalog,lookup=lookup) + report['integrated_guard_100000_seconds']=time.perf_counter()-at + source['animals'][0]['preparations'][0]['cells'][0]['uuid']=expected + from workspace_catalog_identity import CatalogIdentityConflict + try: + with conn.transaction: + conn.query('INSERT INTO `schema`.`identity_rollback_probe` VALUES (3)') + assert_new_catalog_identities(source,probe_catalog,lookup=lookup) + except CatalogIdentityConflict as error: + report['integrated_guard_collision_rejected']=(error.conflict['kind']=='source_uuid_collision' and error.conflict['acquisition_uuid']==expected) + else:report['integrated_guard_collision_rejected']=False + report['integrated_guard_rollback_preserved']=conn.query('SELECT COUNT(*) FROM `schema`.`identity_rollback_probe`').fetchone()[0]==0 + report['helper_cleanup_complete']=not lookup.temporary + conn.query('DROP TEMPORARY TABLE `schema`.`identity_candidates_probe`') + conn.query("SELECT RELEASE_LOCK('recording_workspace_import')") + except Exception as error: + report['runtime_error']={'type':type(error).__name__,'error':str(error),'traceback':traceback.format_exc()};print(traceback.format_exc(),flush=True) + finally: + if dj is not None: + try:dj.conn().close() + except Exception:pass + if project is not None: + try:clean=stop_native_database(project);report['clean_shutdown']=clean + except Exception as error:report['shutdown_error']=str(error) + if clean: + import shutil + shutil.rmtree(temporary);report['temporary_project_removed']=True + else:report['preserved_project']=str(temporary) + report['passed']=not report.get('runtime_error') and clean and all(report.get(key) is True for key in ('connection_local','transaction_rollback_preserved','candidate_insert_rollback_preserved','source_row_count_preserved','advisory_lock_still_owned','helper_rollback_preserved','helper_cleanup_complete','integrated_guard_collision_rejected','integrated_guard_rollback_preserved')) and all(row['equal'] for row in report.get('collation_cases',[])) + args.output.write_text(json.dumps(report,indent=2,default=str)+'\n') + print(json.dumps({key:report[key] for key in ('passed','baseline','candidate_stage_plus_median_seconds','runtime_error') if key in report}),flush=True) + return 0 if report['passed'] else 1 + + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/catalog_identity_native_probe.py b/docs/dev/scale-audit-2026-09-29/catalog_identity_native_probe.py new file mode 100644 index 0000000..b23b769 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/catalog_identity_native_probe.py @@ -0,0 +1,196 @@ +"""Actual pinned population and catalog validator against a disposable native MySQL. + +Creates only a fresh temporary project. Never accepts a project/database address, +never uses Docker, and shuts down its verified owned runtime before removing it. +""" +import argparse +import copy +import datetime as dt +import hashlib +import json +from pathlib import Path +import tempfile +import traceback +import uuid + +from workspace_projects import create_project +from workspace_native_mysql import ensure_native_database, stop_native_database, native_binary +from recording_workspace import connect, assert_new_catalog_identities +import workspace_catalog_identity as validator + + +def fixture(number): + def item(name, **extra): + identity = str(uuid.uuid5(uuid.NAMESPACE_URL, f'rieke-disposable-identity/{number}/{name}')) + return {'uuid':identity, 'label':name, 'properties':{'integer':1,'float':1.0,'boolean':True,'null':None}, + 'attributes':{'uuid':identity}, 'start_time':'06/11/2026 12:34:56:123456', **extra} + source = item('Experiment', rig_type='PATCH', rig='Rig '+str(number), animals=[]) + animal = item('Animal', preparations=[], sex='F', age='42') + preparation = item('Preparation', cells=[], region='central') + source['animals']=[animal]; animal['preparations']=[preparation] + for n in range(2): + cell = item('cell-'+str(n), type='ON', epoch_groups=[]); cell['label']='Cell3' + group = item('group-'+str(n), epoch_blocks=[]) + block = item('block-'+str(n), protocolID='example.Protocol', parameters={}, epochs=[]) + epoch = item('epoch-'+str(n), parameters={'contrast':.5,'control':True,'count':1,'float_count':1.0}, responses={}, stimuli={}) + response = item('response-'+str(n), h5path=f'/experiment/{number}/cell/{n}/epoch/responses/Amp1', + sampleRate=10000.0,sampleRateUnits='Hz', + inputTimeDotNetDateTimeOffsetOffsetHours=-7, + inputTimeDotNetDateTimeOffsetTicks=638853284961234567) + stimulus = item('stimulus-'+str(n), h5path=f'/experiment/{number}/cell/{n}/epoch/stimuli/LED') + epoch['responses']['Amp1']=response;epoch['stimuli']['LED']=stimulus + block['epochs']=[epoch];group['epoch_blocks']=[block];cell['epoch_groups']=[group] + preparation['cells'].append(cell) + return source + + +def main(): + ap=argparse.ArgumentParser(description=__doc__) + ap.add_argument('--output',type=Path,required=True) + ap.add_argument('--strict',action='store_true',help='Return failure for any incorrect scientific outcome, runtime error, or changed helper') + args=ap.parse_args() + if args.output.exists():ap.error('Choose a new output file; historical evidence is preserved') + report={'native':True,'database_scope':'fresh temporary native project only','cases':[], + 'strict':args.strict,'probe_sha256':hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + 'helper_sha256_before':hashlib.sha256(Path(validator.__file__).read_bytes()).hexdigest()} + project=None;dj=None;clean=False + temporary=Path(tempfile.mkdtemp(prefix='rieke-catalog-identity-native-')) + try: + project=Path(create_project(temporary/'projects','Disposable identity probe')['path']) + ensure_native_database(project) + report['mysql_binary']=str(native_binary()) + dj=connect({'kind':'native-project'},project_dir=project) + from retinanalysis.config import schema as catalog + from retinanalysis.utils import database_pop as population + report['pinned_source_sha256']={module.__name__:hashlib.sha256(Path(module.__file__).read_bytes()).hexdigest() + for module in (catalog,population)} + population.configure_tables(catalog) + connection=catalog.schema.connection + report['mysql_version']=connection.query('SELECT VERSION()').fetchone()[0] + report['timestamp_storage_probes']=[] + original_mode=connection.query('SELECT @@SESSION.sql_mode').fetchone()[0] + report['default_sql_mode']=original_mode + connection.query('CREATE TEMPORARY TABLE `schema`.`catalog_timestamp_probe` (stamp DATETIME(0))') + try: + modes=[('server_default',original_mode),('explicit_rounding',','.join(mode for mode in original_mode.split(',') if mode!='TIME_TRUNCATE_FRACTIONAL')), + ('truncate_fractional',','.join(sorted(set(original_mode.split(','))|{'TIME_TRUNCATE_FRACTIONAL'})))] + for mode_name,mode in modes: + connection.query('SET SESSION sql_mode=%s',(mode,)) + for stamp in ('2026-06-11 12:34:56.123456','2026-06-11 12:34:56.499999', + '2026-06-11 12:34:56.500000','2026-06-11 12:34:56.654321', + '2026-06-11 23:59:59.999999'): + connection.query('DELETE FROM `schema`.`catalog_timestamp_probe`') + connection.query('INSERT INTO `schema`.`catalog_timestamp_probe` VALUES (%s)',(dt.datetime.fromisoformat(stamp),)) + stored=connection.query('SELECT stamp FROM `schema`.`catalog_timestamp_probe`').fetchone()[0] + report['timestamp_storage_probes'].append({'mode':mode_name,'input':stamp,'stored':str(stored)}) + finally: + connection.query('SET SESSION sql_mode=%s',(original_mode,)) + connection.query('DROP TEMPORARY TABLE `schema`.`catalog_timestamp_probe`') + sources=[fixture(n) for n in (1,2)] + # The pinned ExperimentObj omits optional scalar keys when unrecorded; + # population should leave these nullable columns NULL, not invent data. + sources[1].pop('rig') + sources[1]['animals'][0]['preparations'][0]['cells'][1]['type']=None + first,second=[cell['epoch_groups'][0] for cell in sources[1]['animals'][0]['preparations'][0]['cells']] + moved=second['epoch_blocks'].pop();moved['protocolID']='other.Protocol' + first['epoch_blocks'].append(moved) # Actual population: one mixed group, one empty group. + with connection.transaction: + for n,source in enumerate(sources): + population.append_experiment(str(temporary/'metadata.json'),str(temporary/f'rig-{n}.h5'), + str(temporary/'tags.json'),source,'disposable-audit',{}) + ids=[(catalog.Experiment & {'h5_uuid':source['uuid']}).fetch1('id') for source in sources] + report['experiment_ids']=[int(value) for value in ids] + def validate(name,source,identity): + try: + counts=validator.validate_catalog_identity(source,catalog,identity) + except Exception as error: + result={'name':name,'accepted':False,'error_type':type(error).__name__,'error':str(error)} + else:result={'name':name,'accepted':True,'counts':counts} + report['cases'].append(result);print(json.dumps(result),flush=True) + return result + for index in range(2):validate('valid_source_'+str(index+1),sources[index],ids[index]) + protocol_names={row['protocol_id']:row['name'] for row in catalog.Protocol.to_dicts()} + report['group_protocol_controls']=[{'group_uuid':row['h5_uuid'],'protocol':protocol_names[row['protocol_id']]} + for row in catalog.EpochGroup.to_dicts()] + stream_relation=catalog.Response & (catalog.Epoch & {'experiment_id':ids[0]}).proj(parent_id='id') + report['response_semijoin_sql']=str(stream_relation.make_sql()) + report['response_semijoin_count']=len(stream_relation) + report['all_response_count']=len(catalog.Response()) + def objects(source): + animal=source['animals'][0];preparation=animal['preparations'][0];cell=preparation['cells'][0] + group=cell['epoch_groups'][0];block=group['epoch_blocks'][0];epoch=block['epochs'][0] + return {'Animal':animal,'Preparation':preparation,'Cell':cell,'EpochGroup':group,'EpochBlock':block, + 'Epoch':epoch,'Response':epoch['responses']['Amp1'],'Stimulus':epoch['stimuli']['LED']} + report['guard_cases']=[] + tables=['Experiment',*objects(sources[0]),'Protocol'] + def inventory(): + return hashlib.sha256(json.dumps({name:getattr(catalog,name).to_dicts() for name in tables}, + sort_keys=True,default=str).encode()).hexdigest() + before_guard=inventory() + for kind in ('distinct_control',*objects(sources[0])): + incoming=fixture(3) + if kind!='distinct_control':objects(incoming)[kind]['uuid']=objects(sources[0])[kind]['uuid'] + try:assert_new_catalog_identities(incoming,catalog) + except Exception as error: + passed=kind!='distinct_control' and isinstance(error,ValueError) and str(error).startswith(f'Existing {kind} source UUID ') + result={'kind':kind,'accepted':False,'passed':passed,'error_type':type(error).__name__,'error':str(error)} + else:result={'kind':kind,'accepted':True,'passed':kind=='distinct_control'} + report['guard_cases'].append(result) + report['guard_preserved_all_catalog_rows']=before_guard==inventory() + group_ids=(catalog.EpochGroup & {'experiment_id':ids[0]}).fetch('id',order_by='id') + group_rows=(catalog.EpochGroup & {'experiment_id':ids[0]}).to_dicts() + mutations=[('swapped_cell_parent',catalog.EpochGroup,'parent_id',group_ids[0],group_rows[1]['parent_id']), + ('wrong_is_mea',catalog.Experiment,'is_mea',ids[0],1), + ('wrong_group_protocol',catalog.EpochGroup,'protocol_id',group_ids[0], + (catalog.Protocol & {'name':'no_group_protocol'}).fetch1('protocol_id')), + ('wrong_rig_scalar',catalog.Experiment,'rig',ids[0],'WRONG RIG'), + ('wrong_epoch_time',catalog.Epoch,'start_time',(catalog.Epoch & {'experiment_id':ids[0]}).fetch('id')[0],'1999-01-01 00:00:00'), + ('wrong_response_offset',catalog.Response,'offset_ticks',stream_relation.fetch('id')[0],'123'), + ('wrong_response_rate',catalog.Response,'sample_rate',stream_relation.fetch('id')[0],'20000')] + for name,table,column,number,value in mutations: + with connection.transaction: + original=(table & {'id':number}).fetch1(column) + connection.query(f'UPDATE {table.full_table_name} SET `{column}`=%s WHERE id=%s',(value,int(number))) + validate(name,sources[0],ids[0]) + connection.query(f'UPDATE {table.full_table_name} SET `{column}`=%s WHERE id=%s',(original,int(number))) + with connection.transaction: + connection.query(f'UPDATE {catalog.Experiment.full_table_name} SET rig=%s WHERE id=%s',('UNRECORDED RIG',int(ids[1]))) + validate('invented_missing_rig',sources[1],ids[1]) + connection.query(f'UPDATE {catalog.Experiment.full_table_name} SET rig=NULL WHERE id=%s',(int(ids[1]),)) + report['stored_time']=str((catalog.Epoch & {'experiment_id':ids[0]}).fetch('start_time')[0]) + report['stored_response_offsets']=stream_relation.fetch1('offset_hours','offset_ticks') if len(stream_relation)==1 else [str(v) for v in stream_relation.fetch('offset_ticks')] + report['valid_after_mutations']=validate('restored_source',sources[0],ids[0])['accepted'] + except Exception as error: + report['runtime_error']={'type':type(error).__name__,'error':str(error),'traceback':traceback.format_exc()} + print(traceback.format_exc(),flush=True) + finally: + if dj is not None: + try:dj.conn().close() + except Exception:pass + if project is not None: + try: + clean=stop_native_database(project) + report['clean_native_shutdown']=clean + except Exception as error:report['shutdown_error']=str(error) + if clean: + import shutil + shutil.rmtree(temporary) + report['temporary_project_removed']=True + else: + report['temporary_project_preserved']=str(temporary) + report['helper_sha256_after']=hashlib.sha256(Path(validator.__file__).read_bytes()).hexdigest() + report['helper_changed_during_run']=report['helper_sha256_before']!=report['helper_sha256_after'] + controls={'valid_source_1','valid_source_2','restored_source'} + report['incorrect_outcomes']=[case['name'] for case in report['cases'] + if (not case['accepted'] if case['name'] in controls else + case['accepted'] or case.get('error_type')!='CatalogIdentityConflict')] + report['scientific_contract_passed']=(len(report['cases'])==11 and not report['incorrect_outcomes'] + and len(report.get('guard_cases',[]))==9 and all(case['passed'] for case in report['guard_cases']) + and report.get('guard_preserved_all_catalog_rows') is True + and not report.get('runtime_error') and clean and not report['helper_changed_during_run']) + report['release_ready']=False + args.output.write_text(json.dumps(report,indent=2,default=str)+'\n') + return 1 if report.get('runtime_error') or not clean or (args.strict and not report['scientific_contract_passed']) else 0 + + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/dense_shared_index_oracle.py b/docs/dev/scale-audit-2026-09-29/dense_shared_index_oracle.py new file mode 100644 index 0000000..ea9111d --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/dense_shared_index_oracle.py @@ -0,0 +1,204 @@ +"""Independent ordinal oracle for the production shared-tag SQLite index. + +This directly exercises the index; generation/record callbacks are deterministic +fixtures, not native SQL or service/browser performance claims. +""" +import argparse +from collections import Counter +import hashlib +import json +import math +from pathlib import Path +import resource +import time +import uuid + +import workspace_shared_tag_index as product + + +def uid(n):return str(uuid.UUID(int=n)) + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--epochs',type=int,default=100000);ap.add_argument('--tags',type=int,default=5);ap.add_argument('--samples',type=int,default=20);ap.add_argument('--aggregates',action='store_true');ap.add_argument('--output',type=Path,required=True);args=ap.parse_args() + if args.output.exists():ap.error('Choose an unused receipt') + if args.tags<5:ap.error('This exact-identity fixture requires at least five tags') + n=args.epochs;profiles=[uid(9000000+p) for p in range(3)];cells=[uid(1000000+c) for c in range((n+99)//100)] + rows=[{'epoch_uuid':uid(100000+i),'cell_uuid':cells[i//100]} for i in range(n)] + epoch_ord={row['epoch_uuid']:i for i,row in enumerate(rows)};cell_ord={value:i for i,value in enumerate(cells)} + epoch_field='annotations/epoch/tags';cell_field='annotations/cell/tags';effective='annotations/effective/tags' + def original(kind,i,p): + if kind=='epoch':return ['common','QC' if i%2==0 else 'qc','é' if i%3==0 else 'e\u0301',f'bucket-{i%17}',f'unique-{i}']+[f'extra-{j}-{p}' for j in range(args.tags-5)] + return ['common','inherited',f'cell-bucket-{i%7}',f'cell-profile-{p}',f'cell-unique-{i}'] + overrides={};state={'generation':0,'epoch':'fixture-v1'};feed={};read_stats={'calls':0,'loaded':0};inject=[False] + def tags_for(kind,i,p):return overrides.get((kind,i,p),original(kind,i,p)) + def make_record(kind,i,p): + tags=tags_for(kind,i,p) + if tags is None:return None + return {'target_kind':kind,'target_uuid':rows[i]['epoch_uuid'] if kind=='epoch' else cells[i], + 'profile_uuid':profiles[p],'author_name':'Same display name' if p<2 else 'Third author', + 'revision':1,'tags':tags} + def records(keys): + read_stats['calls']+=1 + identities=((kind,i,p) for kind,amount in [('cell',len(cells)),('epoch',n)] for i in range(amount) for p in range(3)) if keys is None else ( + (key['target_kind'],(epoch_ord if key['target_kind']=='epoch' else cell_ord)[key['target_uuid']],profiles.index(key['profile_uuid'])) for key in keys) + for kind,i,p in identities: + row=make_record(kind,i,p) + if row is not None: + read_stats['loaded']+=1;yield row + if inject[0]:inject[0]=False;mutate('epoch',n-1,2,['racing','QC']) + def token():return (state['epoch'],state['generation']) + def changes(old): + if old[0]!=state['epoch']:return None + return ([{'target_kind':kind,'target_uuid':rows[i]['epoch_uuid'] if kind=='epoch' else cells[i],'profile_uuid':profiles[p]} + for (kind,i,p),version in feed.items() if version>old[1]],token()) + def mutate(kind,i,p,values): + overrides[(kind,i,p)]=values;state['generation']+=1;feed[(kind,i,p)]=state['generation'] + def validate(row): + assert len(set(row['tags']))==len(row['tags']) and all(isinstance(tag,str) for tag in row['tags']) + assert row['profile_uuid'] in profiles and row['revision']==1 + return row['tags'] + def expected_tags(kind,i):return set().union(*(set(tags_for(kind,i if kind=='epoch' else i//100,p) or []) for p in range(3))) + def summary_oracle(): + tag_counts=Counter();cell_counts=Counter() + for first in range(0,n,100): + present=set() + for i in range(first,min(first+100,n)): + values=expected_tags('epoch',i)|expected_tags('cell',i);tag_counts.update(values);present.update(values) + cell_counts.update(present) + ranked=sorted(tag_counts,key=lambda tag:(-tag_counts[tag],tag.casefold(),tag))[:12] + return {'shared_tagged_cells':len(cells),'shared_tagged_epochs':n, + 'tags':[{'tag':tag,'epoch_count':tag_counts[tag],'cell_count':cell_counts[tag]} for tag in ranked], + 'total_tags':len(tag_counts),'truncated':len(tag_counts)>12} + def catalog_oracle(field): + amount=len(cells) if field==cell_field else n if field in (epoch_field,effective) else 1 + choices=[] + for ordinal in range(min(50,amount)): + i=ordinal*100 if field==cell_field else ordinal + values=sorted(expected_tags('cell',i)) if field==cell_field else sorted(expected_tags('epoch',i)) if field==epoch_field else sorted(expected_tags('epoch',i)|expected_tags('cell',i)) if field==effective else ['Same display name','Third author'] if field=='annotations/authors' else profiles + count=min(100,n-ordinal*100) if field==cell_field else 1 if field in (epoch_field,effective) else n + choices.append({'value':values,'type':'array','count':count}) + return amount,choices + # Independent explicit predicate evaluator. No production matcher is called. + def expected(predicate,i): + if 'all' in predicate:return all(expected(item,i) for item in predicate['all']) + if 'any' in predicate:return any(expected(item,i) for item in predicate['any']) + if 'not' in predicate:return not expected(predicate['not'],i) + field=predicate['field'];values=sorted(expected_tags('epoch',i) if field==epoch_field else expected_tags('cell',i) if field==cell_field else expected_tags('epoch',i)|expected_tags('cell',i)) + op=predicate['operator'];value=predicate.get('value') + if op=='contains':return value in values + if op=='eq':return values==value + if op=='ne':return values!=value + if op=='in':return values in value + if op=='not_in':return values not in value + if op=='exists':return True + if op in ('missing','is_null','gt','gte','lt','lte'):return False + raise AssertionError(op) + def leaf(field,op,value=None):return {'field':field,'operator':op,'value':value} + cases=[('exact_case_upper',leaf(epoch_field,'contains','QC')),('exact_case_lower',leaf(epoch_field,'contains','qc')), + ('unicode_composed',leaf(epoch_field,'contains','é')),('unicode_decomposed',leaf(epoch_field,'contains','e\u0301')), + ('inherited',leaf(cell_field,'contains','cell-bucket-2')),('direct_does_not_inherit',leaf(epoch_field,'contains','inherited')), + ('and',{'all':[leaf(epoch_field,'contains','bucket-3'),leaf(cell_field,'contains','cell-bucket-2')]}), + ('or',{'any':[leaf(epoch_field,'contains','bucket-3'),leaf(cell_field,'contains','cell-bucket-2')]}), + ('scoped_not',{'not':leaf(epoch_field,'contains','bucket-3')}), + ('nested',{'all':[{'any':[leaf(epoch_field,'contains','bucket-3'),leaf(cell_field,'contains','cell-bucket-2')]},{'not':leaf(epoch_field,'contains','unique-503')}]}), + ('empty_array',leaf(effective,'eq',[])),('missing',leaf(effective,'missing')),('numeric_scalar',leaf(epoch_field,'contains',1)), + ('exact_union',leaf(epoch_field,'eq',sorted(expected_tags('epoch',503)))), + ('noncanonical_array_order',leaf(epoch_field,'eq',list(reversed(sorted(expected_tags('epoch',503)))))), + ('repeated_array_tag',leaf(epoch_field,'eq',['common','common'])), + ('array_in',leaf(epoch_field,'in',[[],sorted(expected_tags('epoch',503))])), + ('array_not_in',leaf(epoch_field,'not_in',[[],sorted(expected_tags('epoch',503))]))] + source_hash=hashlib.sha256(Path(product.__file__).read_bytes()).hexdigest() + def timings_summary(values): + ordered=sorted(values) + return {'samples':len(values),'quantile_method':'nearest_rank', + **{'p'+str(int(q*100)):ordered[max(0,math.ceil(q*len(ordered))-1)] for q in (.5,.95,.99)}, + 'maximum':max(values),'sample_seconds':values} + manifest={'epochs':n,'profiles':profiles,'tags_per_epoch_profile':args.tags,'cell_tags_per_profile':5,'formula_version':2} + report={'scope':__doc__,'fixture':manifest,'fixture_sha256':hashlib.sha256(json.dumps(manifest,sort_keys=True).encode()).hexdigest(), + 'source_sha256_before':source_hash,'probe_sha256':hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),'cases':[],'release_ready':False} + index=product.SharedTagIndex(generation=token,changes=changes,records=records,validate=validate) + def check(name,condition,**detail): + item={'name':name,'passed':bool(condition),**detail};report['cases'].append(item);print(json.dumps(item),flush=True) + if not condition:raise AssertionError(name) + try: + start=time.perf_counter();check('cold_build',index.refresh());report['cold_build_seconds']=time.perf_counter()-start + full_loaded=read_stats['loaded'];check('all_profiles_indexed',full_loaded==3*(n+len(cells)),loaded=full_loaded) + if hasattr(index,'storage_stats'):report['storage_after_build']=index.storage_stats() + if args.aggregates: + # Product overview ordering follows the established casefold then + # exact-text tie rule, independently reproduced from ordinal sets. + wanted=summary_oracle() + start=time.perf_counter();actual=index.summary(rows);report['cold_summary_seconds']=time.perf_counter()-start + check('summary_independent_exact_counts',actual==wanted,seconds=report['cold_summary_seconds']) + fields=[cell_field,epoch_field,effective,'annotations/authors','annotations/author_uuids'] + start=time.perf_counter();catalog=index.catalog(rows,fields);report['cold_catalog_seconds']=time.perf_counter()-start + for field in fields: + amount,choices=catalog_oracle(field) + actual=catalog[field] + check('catalog_'+field,actual['count']==n and actual['distinct_count']==amount and actual['choices']==choices and actual['choices_truncated']==(amount>50),distinct=actual['distinct_count']) + summary_times=[];catalog_times=[] + for _ in range(args.samples): + start=time.perf_counter();assert index.summary(rows)==wanted;summary_times.append(time.perf_counter()-start) + start=time.perf_counter();assert index.catalog(rows,fields)==catalog;catalog_times.append(time.perf_counter()-start) + for name,values in [('summary',summary_times),('catalog',catalog_times)]: + report['warm_'+name+'_seconds']=timings_summary(values) + if hasattr(index,'storage_stats'):report['storage_after_aggregates']=index.storage_stats() + for name,predicate in cases: + eligible=rows[37::3] if name=='scoped_not' else rows + wanted=tuple(row['epoch_uuid'] for row in eligible if expected(predicate,epoch_ord[row['epoch_uuid']])) + start=time.perf_counter();actual,_=index.matching(eligible,{},predicate);seconds=time.perf_counter()-start + check(name,actual==wanted,matched=len(actual),query_seconds=seconds,uuid_sha256=hashlib.sha256(''.join(actual).encode()).hexdigest()) + # Membership queries load no canonical annotation rows after refresh. + timings=[] + for _ in range(args.samples): + start=time.perf_counter();assert index.refresh();result,_=index.matching(rows,{'tag':'bucket-3'});timings.append(time.perf_counter()-start) + check('warm_queries_read_zero_annotation_rows',read_stats['loaded']==full_loaded) + report['warm_match_seconds']=timings_summary(timings) + for count in (1,1000): + before=read_stats['loaded'];start=time.perf_counter() + for i in range(min(count,n)):mutate('epoch',i,0,['QC','modified']) + assert index.refresh();elapsed=time.perf_counter()-start + actual,_=index.matching(rows,{'tag':'modified'});wanted=tuple(row['epoch_uuid'] for row in rows[:min(count,n)]) + check(f'delta_{count}_same_revision',actual==wanted and read_stats['loaded']-before==min(count,n),rows_loaded=read_stats['loaded']-before,refresh_seconds=elapsed) + if args.aggregates: + wanted_summary=summary_oracle();start=time.perf_counter();actual_summary=index.summary(rows);summary_seconds=time.perf_counter()-start + start=time.perf_counter();actual_catalog=index.catalog(rows,fields);catalog_seconds=time.perf_counter()-start + good=actual_summary==wanted_summary + for field in fields: + amount,choices=catalog_oracle(field);good=good and actual_catalog[field]['distinct_count']==amount and actual_catalog[field]['choices']==choices + check(f'delta_{count}_aggregates_remain_exact',good,summary_seconds=summary_seconds,catalog_seconds=catalog_seconds) + if hasattr(index,'storage_stats'):report[f'storage_after_delta_{count}']=index.storage_stats() + for p in range(3):mutate('epoch',0,p,[]);mutate('cell',0,p,[]) + assert index.refresh();actual,_=index.matching(rows,{},leaf(effective,'eq',[])) + check('empty_tag_rows_and_inheritance_removed',actual==(rows[0]['epoch_uuid'],)) + for p in range(3):mutate('epoch',1,p,None) + assert index.refresh();actual,_=index.matching(rows,{},leaf(epoch_field,'eq',[])) + check('deleted_records_leave_exact_empty_membership',actual==(rows[0]['epoch_uuid'],rows[1]['epoch_uuid'])) + old_token=index.token;mutate('epoch',2,0,['race fixture']);inject[0]=True + try:index.refresh() + except product.SharedTagsChanged:conflict=True + else:conflict=False + check('mixed_generation_build_rejected',conflict and index.token==old_token) + assert index.refresh();actual,_=index.matching(rows,{'tag':'racing'});check('subsequent_delta_recovers_exact_membership',actual==(rows[-1]['epoch_uuid'],)) + report['stats']=index.stats;report['sqlite_bytes']=sum(path.stat().st_size for path in Path(index.folder.name).iterdir()) + report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + report['source_sha256_after']=hashlib.sha256(Path(product.__file__).read_bytes()).hexdigest();report['source_unchanged']=source_hash==report['source_sha256_after'] + report['passed']=report['source_unchanged'] and all(item['passed'] for item in report['cases']) + except Exception as error: + import traceback + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};report['passed']=False;print(traceback.format_exc(),flush=True) + finally: + folder=Path(index.folder.name) if index.folder is not None else None;connection=index.connection + index.close();report['derived_folder_removed']=folder is None or not folder.exists() + closed=connection is None + if connection is not None: + try:connection.execute('SELECT 1') + except Exception:closed=True + report['sqlite_connection_closed']=closed + report['passed']=report.get('passed',False) and report['derived_folder_removed'] and closed + args.output.write_text(json.dumps(report,indent=2)+'\n') + return int(not report['passed']) + + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/freeze_validation.py b/docs/dev/scale-audit-2026-09-29/freeze_validation.py new file mode 100644 index 0000000..7e94464 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/freeze_validation.py @@ -0,0 +1,288 @@ +"""Capture checked source copies and validate that fixed snapshot, preserving evidence. + +The snapshot is assembled in a temporary directory, checked against source hashes +before and after copying, then retained with results. No checkout/branch changes. +Only Python runtime binaries and node_modules are symlinked; application/parser +source is copied. External installed dependencies are hashed before/after use. +""" +from __future__ import annotations + +import argparse +import datetime as dt +import hashlib +import importlib.metadata +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys +import tempfile +import time + +HERE = Path(__file__).resolve().parent +REPO = HERE.parents[2] +AUDIT = HERE.relative_to(REPO) +IGNORED = {'__pycache__', '.git', '.pytest_cache', '.DS_Store'} + + +def digest(path): + with path.open('rb') as stream: + return hashlib.file_digest(stream, 'sha256').hexdigest() + + +def checksum(value): + return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(',', ':')).encode()).hexdigest() + + +def write_json(path, value): + path.write_text(json.dumps(value, indent=2, sort_keys=True) + '\n') + + +def walk(folder, *, dependency=False): + if not folder.exists(): + raise FileNotFoundError(folder) + ignored = IGNORED | ({'.cache', '.vite', '.vite-temp'} if dependency else set()) + for current, directories, files in os.walk(folder, followlinks=False): + directories[:] = sorted(name for name in directories if name not in ignored) + for name in sorted(files): + path = Path(current) / name + if name in ignored or path.suffix in {'.pyc', '.pyo'}: + continue + yield path + for name in directories: + path = Path(current) / name + if path.is_symlink(): + # Do not silently omit a tree that may contain executed code. + raise ValueError('Directory symlink requires explicit dependency handling: ' + str(path)) + + +def source_inventory(): + paths = set() + for folder in ('python', 'tools', 'tests', 'src', 'workspace-app/src', 'workspace-app/public'): + paths.update(walk(REPO / folder)) + for path in (REPO / 'workspace-app').iterdir(): + if path.is_file(): + paths.add(path) + for name in ('rieke-release.json', 'rieke.py', 'README.md', 'LICENSE', 'epicTreeGUI.m', 'install.m'): + paths.add(REPO / name) + paths.update(HERE.glob('*.py')) + paths.update(HERE.glob('*.mjs')) + parser_root = REPO / '.rieke-runtime/retinanalysis' + paths.update(path for path in walk(parser_root) if path.suffix == '.py') + paths.update(parser_root / name for name in ('pyproject.toml', 'LICENSE.txt')) + result = {} + for path in sorted(paths): + if path.is_symlink(): + raise ValueError('Application/parser source must be copied from a regular file: ' + str(path)) + result[str(path.relative_to(REPO))] = digest(path) + return result + + +def dependency_inventory(python_packages, node_modules, python_binary, node_binary): + result = {'python_binary': digest(python_binary), 'node_binary': digest(node_binary), 'files': {}} + for label, root in (('python_packages', python_packages), ('node_modules', node_modules)): + for path in walk(root, dependency=True): + entry = {'sha256': digest(path)} + if path.is_symlink(): + target = path.resolve(strict=True) + if not target.is_relative_to(root.resolve()): + raise ValueError('Dependency link escapes its recorded root: ' + str(path)) + entry['symlink_target'] = os.readlink(path) + result['files'][label + '/' + str(path.relative_to(root))] = entry + return result + + +def mysql_inventory(prefix): + """Hash the explicitly reused native runtime, never a database directory.""" + values = {} + for directory, folders, files in os.walk(prefix, followlinks=False): + for name in sorted(files + [n for n in folders if (Path(directory) / n).is_symlink()]): + path = Path(directory) / name + relative = str(path.relative_to(prefix)) + if path.is_symlink(): + values[relative] = {'symlink': os.readlink(path)} + if path.is_file(): + values[relative]['sha256'] = digest(path) + elif path.is_file(): + values[relative] = {'sha256': digest(path)} + return values + + +def capture(output, retries): + attempts = [] + for number in range(1, retries + 1): + before = source_inventory() + with tempfile.TemporaryDirectory(prefix='rieke-frozen-source-') as temporary: + snapshot = Path(temporary) / 'snapshot' + snapshot.mkdir() + for name in before: + destination = snapshot / name + destination.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(REPO / name, destination) + copied = {name: digest(snapshot / name) for name in before} + after = source_inventory() + changed = sorted(name for name in before.keys() | after.keys() + if before.get(name) != after.get(name) or copied.get(name) != before.get(name)) + attempts.append({'attempt': number, 'changed_paths': changed}) + if changed: + print(f'Snapshot attempt {number} changed during copying; retrying', flush=True) + continue + destination = output / 'snapshot' + shutil.move(str(snapshot), destination) + # Check the retained files too, including any cross-filesystem move. + if {name: digest(destination / name) for name in before} != before: + raise ValueError('Retained snapshot differs from its checked source copy') + return destination, before, attempts + write_json(output / 'snapshot-rejected.json', {'attempts': attempts, 'release_ready': False}) + raise RuntimeError('Could not capture a stable source snapshot within the retry limit') + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--epochs', type=int, default=100000) + parser.add_argument('--output-dir', type=Path, required=True) + parser.add_argument('--copy-attempts', type=int, default=3) + parser.add_argument('--native-dense', action='store_true', + help='Also run the disposable native 5-tag API/backup benchmark against copied application source') + parser.add_argument('--physical-manifest', type=Path, + help='Read-only imported recording manifest for the ancestor-metadata round-trip oracle') + parser.add_argument('--physical-block', help='Exact block UUID to verify with --physical-manifest') + args = parser.parse_args() + if not 100 <= args.epochs <= 1000000 or not 1 <= args.copy_attempts <= 5: + parser.error('epochs must be 100–1000000; copy-attempts must be 1–5') + if bool(args.physical_manifest) != bool(args.physical_block): + parser.error('physical-manifest and physical-block must be provided together') + output = args.output_dir.resolve() + output.mkdir(parents=True, exist_ok=False) # Preserve every earlier run. + started = dt.datetime.now(dt.timezone.utc).isoformat() + print('Capturing checked source snapshot', flush=True) + snapshot, hashes, attempts = capture(output, args.copy_attempts) + python_binary = Path(sys.executable).resolve(strict=True) + node_binary = Path(shutil.which('node') or '').resolve(strict=True) + python_packages = Path(sys.prefix) / f'lib/python{sys.version_info.major}.{sys.version_info.minor}/site-packages' + node_modules = REPO / 'workspace-app/node_modules' + if not python_packages.is_dir() or not node_binary.is_file(): + raise ValueError('Run with the installed project venv and Node runtime') + + # A minimal isolated venv avoids executing installed editable .pth files that + # point at live application/parser source. Packages are on PYTHONPATH directly. + venv = snapshot / '.rieke-runtime/venv' + (venv / 'bin').mkdir(parents=True) + (venv / f'lib/python{sys.version_info.major}.{sys.version_info.minor}/site-packages').mkdir(parents=True) + (venv / 'pyvenv.cfg').write_text(f'home = {python_binary.parent}\ninclude-system-site-packages = false\nversion = {sys.version.split()[0]}\n') + for name in ('python', 'python3', f'python{sys.version_info.major}.{sys.version_info.minor}'): + (venv / 'bin' / name).symlink_to(python_binary) + (snapshot / 'workspace-app/node_modules').symlink_to(node_modules, target_is_directory=True) + runtime_bin = output / 'runtime-bin' + runtime_bin.mkdir() + (runtime_bin / 'node').symlink_to(node_binary) + env = dict(os.environ) + env.pop('PYTHONHOME', None) + env.pop('NODE_PATH', None) + env.pop('NODE_OPTIONS', None) + env['PYTHONPATH'] = os.pathsep.join(map(str, [snapshot / 'python', snapshot / 'python/tests', + snapshot / '.rieke-runtime/retinanalysis/src', python_packages])) + env['PYTHONDONTWRITEBYTECODE'] = '1' + env['PYTHONNOUSERSITE'] = '1' + env['PATH'] = str(runtime_bin) + os.pathsep + env.get('PATH', '') + # This runner certifies the explicitly implemented disposable gates only. + # Never inherit opt-in flags that could start a native integration workload. + disabled_opt_ins = {key: env.pop(key) for key in list(env) if key.startswith('RIEKE_TEST_')} + interpreter = venv / 'bin/python' + probe = subprocess.run([str(interpreter), '-c', + 'import sys,json,importlib.util,importlib.metadata; ' + 'print(json.dumps({"python":sys.version,"prefix":sys.prefix,"sys_path":sys.path,' + '"modules":{n:importlib.util.find_spec(n).origin for n in ' + '["workspace_service","retinanalysis","h5py","bin2py"]},' + '"packages":sorted((d.metadata["Name"],d.version) for d in importlib.metadata.distributions())}))'], + cwd=snapshot, env=env, text=True, capture_output=True, check=True) + runtime = json.loads(probe.stdout) + for name in ('workspace_service', 'retinanalysis'): + if not Path(runtime['modules'][name]).is_relative_to(snapshot): + raise ValueError('Snapshot resolved live application code: ' + name) + runtime['node_version'] = subprocess.check_output([str(node_binary), '--version'], text=True).strip() + runtime['external_roots'] = {'python_packages': str(python_packages), 'node_modules': str(node_modules), + 'python_binary': str(python_binary), 'node_binary': str(node_binary)} + runtime['disabled_native_test_flags'] = sorted(disabled_opt_ins) + print('Hashing external dependency files before validation', flush=True) + dependencies = dependency_inventory(python_packages, node_modules, python_binary, node_binary) + write_json(output / 'dependencies.json', dependencies) + write_json(output / 'runtime.json', runtime) + manifest = {'original_root': str(REPO), 'snapshot_root': str(snapshot), 'started_at': started, + 'source_sha256': hashes, 'source_manifest_sha256': checksum(hashes), 'copy_attempts': attempts, + 'dependency_manifest_sha256': checksum(dependencies), + 'mapping': 'Every source_sha256 key maps original_root/key to snapshot_root/key; all are copied regular files.', + 'external_dependencies': 'Installed Python packages and Node modules are reused and checked before/after; editable .pth files are not executed.', + 'coherence_limit': 'Equal inventories before/after copying and copied-file hashes establish an observed stable capture; this is not an operating-system transactional filesystem snapshot.'} + write_json(output / 'source-manifest.json', manifest) + mysql_root = None + mysql_before = None + if args.native_dense: + sys.path.insert(0, str(REPO / 'python')) + from workspace_mysql_runtime import mysql_runtime + mysql_root = Path(mysql_runtime(root=REPO)['root']).resolve() + mysql_before = mysql_inventory(mysql_root) + write_json(output / 'native-runtime.json', {'root': str(mysql_root), 'files': mysql_before, + 'scope': 'Runtime executables/assets reused; all app/parser source comes from the copied snapshot. Database is newly created and destroyed by the harness.'}) + gates = output / 'gates' + command = [str(interpreter), str(snapshot / AUDIT / 'run_stress_gates.py'), + '--epochs', str(args.epochs), '--output-dir', str(gates)] + print('Running fixed-snapshot strict gates', flush=True) + timer = time.perf_counter() + with (output / 'runner.log').open('w') as log: + completed = subprocess.run(command, cwd=snapshot, env=env, stdout=log, stderr=subprocess.STDOUT) + native_code = None + if args.native_dense: + print('Running fixed-snapshot native dense-tag API benchmark', flush=True) + native_env = {**env, 'PYTHONPATH': str(snapshot / AUDIT) + os.pathsep + env['PYTHONPATH']} + with (output / 'native-dense.log').open('w') as log: + native = subprocess.run([str(interpreter), str(snapshot / AUDIT / 'benchmark_native_dense_tags.py'), + '--epochs', str(args.epochs), '--samples', '20', '--edits', '20', '--tags', '5', + '--mysql-runtime-root', str(mysql_root), '--output', str(output / 'native-dense.json')], + cwd=snapshot, env=native_env, stdout=log, stderr=subprocess.STDOUT) + native_code = native.returncode + physical_code = None + if args.physical_manifest: + print('Running fixed-snapshot read-only physical metadata oracle', flush=True) + with (output / 'physical-metadata.log').open('w') as log: + physical = subprocess.run([str(interpreter), str(snapshot / AUDIT / 'metadata_ancestor_physical_oracle.py'), + '--manifest', str(args.physical_manifest.resolve()), '--block-uuid', args.physical_block, + '--output', str(output / 'physical-metadata.json')], + cwd=snapshot, env=env, stdout=log, stderr=subprocess.STDOUT) + physical_code = physical.returncode + print('Checking snapshot and external dependencies after validation', flush=True) + source_changes = [name for name, sha in hashes.items() + if not (snapshot / name).is_file() or digest(snapshot / name) != sha] + after_dependencies = dependency_inventory(python_packages, node_modules, python_binary, node_binary) + dependency_changes = sorted(name for name in dependencies['files'].keys() | after_dependencies['files'].keys() + if dependencies['files'].get(name) != after_dependencies['files'].get(name)) + for name in ('python_binary', 'node_binary'): + if dependencies[name] != after_dependencies[name]: + dependency_changes.append(name) + summary = json.loads((gates / 'summary.json').read_text()) if (gates / 'summary.json').exists() else {} + passed = completed.returncode == 0 and summary.get('implemented_gates_passed') is True and not source_changes and not dependency_changes + mysql_changes = [] + if args.native_dense: + mysql_after = mysql_inventory(mysql_root) + mysql_changes = sorted(name for name in mysql_before.keys() | mysql_after.keys() + if mysql_before.get(name) != mysql_after.get(name)) + passed = passed and native_code == 0 and not mysql_changes + if args.physical_manifest: + passed = passed and physical_code == 0 + result = {'epochs': args.epochs, 'captured_source_manifest_sha256': checksum(hashes), + 'snapshot_gate_exit_code': completed.returncode, 'implemented_gates_passed': passed, + 'snapshot_source_changed_during_run': source_changes, 'external_dependencies_changed_during_run': dependency_changes, + 'native_dense_exit_code': native_code, 'native_runtime_changed_during_run': mysql_changes, + 'physical_metadata_exit_code': physical_code, + 'seconds': time.perf_counter() - timer, 'gate_summary': 'gates/summary.json', + 'retained_snapshot': 'snapshot', 'release_ready': False, + 'required_unexecuted_trials': summary.get('required_unexecuted_trials', ['Gate runner did not produce a summary']), + 'scope': 'Only the captured code was validated. Later edits to the original workspace are not covered.'} + write_json(output / 'summary.json', result) + print(json.dumps(result, indent=2), flush=True) + return 0 if passed else 1 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/frontend-benchmark.mjs b/docs/dev/scale-audit-2026-09-29/frontend-benchmark.mjs new file mode 100644 index 0000000..3479d5e --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/frontend-benchmark.mjs @@ -0,0 +1,63 @@ +// Disposable synthetic audit. No production requests, source data, or app changes. +import {createRequire} from 'node:module'; +import {fileURLToPath} from 'node:url'; +import {writeFile} from 'node:fs/promises'; +import os from 'node:os'; +import {performance} from 'node:perf_hooks'; +const root=fileURLToPath(new URL('../../../workspace-app/',import.meta.url)); +const require=createRequire(root+'package.json'); +const {createElement}=require('react'); +const {renderToString}=require('react-dom/server'); +const {createServer}=await import(require.resolve('vite')); +const {default:react}=await import(require.resolve('@vitejs/plugin-react')); +const {createResourceCache,cachedResourceRequest,initialEpochTracePath}=await import('../../../workspace-app/src/resourceCache.js'); +const {finiteExtent}=await import('../../../workspace-app/src/components/traceGeometry.js'); +const {registeredMetadataField}=await import('../../../workspace-app/src/components/metadataValues.js'); +const {groupedCellPage}=await import('../../../workspace-app/src/boundedTree.js'); +const output={measured_at:new Date().toISOString(),machine:{node:process.version,platform:process.platform,arch:process.arch,cpu:os.cpus()[0]?.model,total_memory_gib:os.totalmem()/2**30},limitations:['Node SSR and synthetic helper timings, not browser paint / INP / H5 throughput.','No production API requests or original data read; generated identities and metadata only.','Synthetic large catalogs put inspected fields near the end to expose repeated linear search cost.'],measurements:[]}; +const previous=console.error;console.error=(message,...args)=>{if(!String(message).startsWith('Warning: useLayoutEffect does nothing on the server'))previous(message,...args);}; +const server=await createServer({root,configFile:false,plugins:[react()],server:{middlewareMode:true,hmr:false},appType:'custom',logLevel:'error'}); +try{ + const {default:InspectionCellTree}=await server.ssrLoadModule('/src/components/InspectionCellTree.jsx'); + const {CellList}=await server.ssrLoadModule('/src/components/Common.jsx'); + const {default:MetadataPanel}=await server.ssrLoadModule('/src/components/MetadataPanel.jsx'); + const {default:Overview}=await server.ssrLoadModule('/src/components/Overview.jsx'); + function measure(name,size,run,repeats=3){ + const samples=[];let result; + for(let i=0;ia-b),row={name,size,samples_ms:samples,median_ms:sorted[Math.floor(sorted.length/2)],result};output.measurements.push(row);console.log(JSON.stringify(row));return row; + } + const cells=n=>Array.from({length:n},(_,i)=>({cell_uuid:`cell-${i}`,label:`Cell${i}`,date:`2026-09-${String(1+i%28).padStart(2,'0')}`,cell_type:['On Parasol','Off Parasol','Midget'][i%3],epochs:100,duration_seconds:500})); + for(const n of [100,1000,10000,50000]){ + const records=cells(n),props={cells:records,targets:[],source:{kind:'protocol',protocolId:'synthetic',query:''},revision:0}; + measure('default InspectionCellTree SSR; all dates closed',n,()=>{const html=renderToString(createElement(InspectionCellTree,props));return {cell_details_elements:(html.match(/class="cell-tree-cell"/g)||[]).length,html_bytes:Buffer.byteLength(html)};}); + measure('bounded CellList SSR',n,()=>{const html=renderToString(createElement(CellList,{cells:records}));return {cell_rows:(html.match(/class="cell-row"/g)||[]).length,html_bytes:Buffer.byteLength(html)};}); + measure('groupedCellPage helper',n,()=>{const page=groupedCellPage(records,0);return {total:page.total,visible:page.groups.reduce((sum,g)=>sum+g.cells.length,0)};}); + } + for(const n of [100,1000,5000]){ + const protocols=Array.from({length:n},(_,i)=>({protocol_uuid:`protocol-${i}`,name:`Synthetic Protocol ${i}`,counts:{epochs:i+1,cells:5,duration_seconds:100}})); + measure('Overview SSR varying protocol count',n,()=>{const html=renderToString(createElement(Overview,{data:{cells:[],protocols,counts:{},sources:[],events:[]}}));return {protocol_rows:(html.match(/class="ov-protocol-row"/g)||[]).length,html_bytes:Buffer.byteLength(html)};}); + measure('ProtocolVolumes current exact max-per-row expression',n,()=>{let sum=0;for(const protocol of protocols){const count=protocol.counts?.epochs??protocol.epoch_count??0;sum+=count/Math.max(1,...protocols.map(item=>item.counts?.epochs??item.epoch_count??0))*100;}return {sum};}); + measure('proposed max-once expression',n,()=>{const max=Math.max(1,...protocols.map(item=>item.counts?.epochs??item.epoch_count??0));let sum=0;for(const protocol of protocols)sum+=(protocol.counts?.epochs??protocol.epoch_count??0)/max*100;return {sum};}); + } + for(const n of [100,1000,10000]){ + const fields=Array.from({length:n},(_,i)=>({id:`parameters/p${i}`,grouping_priority:i,grouping_role:'technical'})); + const parameters=Object.fromEntries(Array.from({length:100},(_,i)=>[`p${n-100+i}`,i])); + measure('MetadataPanel SSR 100 parameters near end of field catalog',n,()=>{const html=renderToString(createElement(MetadataPanel,{epoch:{epoch_uuid:'synthetic',parameters},catalog:{data:{fields}}}));return {html_bytes:Buffer.byteLength(html)};}); + const paths=Object.keys(parameters).map(key=>['parameters',key]); + measure('100 registeredMetadataField lookups',n,()=>({found:paths.filter(path=>registeredMetadataField(path,fields)).length})); + measure('proposed predecoded field map plus 100 lookups',n,()=>{const index=new Map(fields.map(field=>[JSON.stringify(field.id.split('/').map(part=>decodeURIComponent(part).replace(/~1/g,'/').replace(/~0/g,'~'))),field]));return {found:paths.filter(path=>index.has(JSON.stringify(path))).length};}); + } + const values=Array.from({length:20000},(_,i)=>Math.sin(i/20)*50); + measure('bounded 20k trace finiteExtent',20000,()=>finiteExtent(values),5); + measure('bounded 20k trace JSON stringify + parse',20000,()=>{const parsed=JSON.parse(JSON.stringify({values}));return {samples:parsed.values.length};},5); + const cache=createResourceCache(); + measure('bounded 20k trace cache put including serialization estimate',20000,()=>{cache.put('/epochs/synthetic/trace',0,{values});return cache.stats();},5); + let requests=0;const duplicateCache=createResourceCache();const request=async()=>{requests++;await new Promise(resolve=>setTimeout(resolve,10));return {epoch_uuid:'synthetic'};}; + await Promise.all([cachedResourceRequest('/epochs/synthetic',{cache:duplicateCache,request}),cachedResourceRequest('/epochs/synthetic',{cache:duplicateCache,request})]); + output.duplicate_miss={concurrent_same_key_calls:2,underlying_request_calls:requests}; + output.trace_window={full_stream_samples:100000000,initial_path:initialEpochTracePath({epoch_uuid:'synthetic',streams:[{kind:'responses',uuid:'response',sample_count:100000000}]})}; + const boundedCache=createResourceCache();for(let i=0;i<1000;i++)boundedCache.put(`/epochs/synthetic-${i}`,0,{values});output.cache_after_1000_trace_sized_entries=boundedCache.stats(); + // Matches Inspector.jsx's Promise.all(uuids.map(api(...))) fan-out, without network. + for(const n of [1,60,1000]){let active=0,peak=0;await Promise.all(Array.from({length:n},async()=>{active++;peak=Math.max(peak,active);await new Promise(resolve=>setTimeout(resolve,1));active--;}));output.measurements.push({name:'Inspector curation Promise.all GET fan-out simulation',size:n,peak_concurrent_calls:peak});} +}finally{await server.close();console.error=previous;await writeFile(new URL('./frontend-benchmark.json',import.meta.url),JSON.stringify(output,null,2)+'\n');} diff --git a/docs/dev/scale-audit-2026-09-29/frontend-selection-race.mjs b/docs/dev/scale-audit-2026-09-29/frontend-selection-race.mjs new file mode 100644 index 0000000..a7bbbd1 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/frontend-selection-race.mjs @@ -0,0 +1,22 @@ +// Mounted React lifecycle recovery gate; never contacts a production API. +// Default writes diagnostic JSON; --strict fails on any stale publication. +import {writeFile} from 'node:fs/promises'; +import {selectionRaceCases} from '../../../workspace-app/src/test-support/pagedTreeHarness.js'; +const strict=process.argv.includes('--strict'); +let output; +for(let i=2;iitem.kind==='cell'&&item.change==='filter'); +const failures=cases.flatMap(item=>item.assertions.filter(a=>!a.passed).map(a=>({case:`${item.kind}:${item.change}`,assertion:a.name}))); +// Preserve the original default diagnostic keys for existing readers. +const result={kind:'Mounted PagedTree React lifecycle with deferred fake API, not browser E2E',started_filter:filterCell.started_filter,current_filter:filterCell.current_filter, + old_request_aborted:filterCell.old_request_aborted,published_after_filter_change:filterCell.published_after_rerender.map(({phase,...rest})=>rest), + lifecycle:'Real React mount, update, layout effects and unmount; child presentation and API are fixtures.', + cases,gate:{strict,passed:failures.length===0,failures,description:'Late cell/range completion must retain current scope and exact UUIDs.'}}; +console.log(JSON.stringify(result,null,2)); +await writeFile(output||new URL(strict?'./frontend-selection-race.strict.json':'./frontend-selection-race.json',import.meta.url),JSON.stringify(result,null,2)+'\n'); +if(strict&&failures.length)process.exitCode=1; diff --git a/docs/dev/scale-audit-2026-09-29/metadata-field-index.fixed.mjs b/docs/dev/scale-audit-2026-09-29/metadata-field-index.fixed.mjs new file mode 100644 index 0000000..cb59d45 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/metadata-field-index.fixed.mjs @@ -0,0 +1,19 @@ +// Synthetic read-only comparison; no production API or recordings. +import assert from 'node:assert/strict'; +import {performance} from 'node:perf_hooks'; +import {writeFile} from 'node:fs/promises'; +import {registeredMetadataField} from '../../../workspace-app/src/components/metadataValues.js'; +const fields=Array.from({length:10000},(_,i)=>({id:`parameters/p${i}`})); +const paths=Array.from({length:100},(_,i)=>['parameters',`p${9900+i}`]); +function original(path,fields){return fields.find(field=>{ + if(!field.id.includes('/'))return path.length===1&&field.path===path[0]; + try{const parts=field.id.split('/').map(part=>decodeURIComponent(part).replace(/~1/g,'/').replace(/~0/g,'~'));return parts.length===path.length&&parts.every((part,index)=>part===path[index]);}catch{return false;} +});} +const measure=run=>{const start=performance.now();const found=paths.map(run);assert.deepEqual(found,fields.slice(9900));return performance.now()-start;}; +const cold=measure(path=>registeredMetadataField(path,fields)); +const samples=Array.from({length:5},()=>measure(path=>registeredMetadataField(path,fields))); +const originalSamples=Array.from({length:3},()=>measure(path=>original(path,fields))); +const median=values=>[...values].sort((a,b)=>a-b)[Math.floor(values.length/2)]; +const result={measured_at:new Date().toISOString(),node:process.version,platform:process.platform,arch:process.arch,field_count:fields.length,lookup_count:paths.length,cold_index_and_lookups_ms:cold,warm_lookup_samples_ms:samples,warm_lookup_median_ms:median(samples),original_scan_samples_ms:originalSamples,original_scan_median_ms:median(originalSamples),exact_field_identity_order_preserved:true,limitations:['Synthetic helper measurement, not browser commit time or end-to-end latency.','Original comparator is the pre-change lookup expression; both implementations return the exact same 100 field objects.']}; +console.log(JSON.stringify(result,null,2)); +await writeFile(new URL('./metadata-field-index.fixed.json',import.meta.url),JSON.stringify(result,null,2)+'\n'); diff --git a/docs/dev/scale-audit-2026-09-29/metadata_ancestor_physical_oracle.py b/docs/dev/scale-audit-2026-09-29/metadata_ancestor_physical_oracle.py new file mode 100644 index 0000000..624d6b8 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/metadata_ancestor_physical_oracle.py @@ -0,0 +1,195 @@ +"""Read-only physical-source metadata oracle; all derived artifacts are disposable. + +Reads already imported acquisition metadata and H5 owner identities. It tests +normalization, not parser correctness or waveform values. The duplicated-detail +comparison is a controlled representation clone of the current index schema, +not an executable historical product build. +""" +import argparse +import copy +import datetime as dt +import hashlib +import json +from pathlib import Path +import resource +import shutil +import sqlite3 +import statistics +import tempfile +import threading +import time +import traceback +import uuid +import zlib + +import h5py +from workspace_disk_index import DiskMetadataIndex +from workspace_projection_cache import ProjectionCache +from workspace_recipes import checksum +import workspace_metadata_objects as objects +import workspace_disk_index as disk_module +import workspace_projection_cache as projection_module + + +def raw(value):return json.dumps(value,sort_keys=True,ensure_ascii=False,separators=(',',':'),allow_nan=False).encode() +def sha(path): + value=hashlib.sha256() + with open(path,'rb') as stream: + for block in iter(lambda:stream.read(1024*1024),b''):value.update(block) + return value.hexdigest() +def signature(path): + stat=Path(path).stat();return [stat.st_dev,stat.st_ino,stat.st_size,stat.st_mtime_ns,stat.st_ctime_ns] +def storage(path): + files=[path] if path.is_file() else [item for item in path.rglob('*') if item.is_file() and not item.is_symlink()] + return {'apparent_bytes':sum(item.stat().st_size for item in files),'allocated_bytes':sum(item.stat().st_blocks*512 for item in files),'files':len(files)} +def date(value): + for pattern in ('%m/%d/%Y','%Y-%m-%d'): + try:return dt.datetime.strptime(value[:10],pattern).date().isoformat() + except ValueError:pass + raise ValueError('Unsupported source date') +def identity(value):return str(uuid.UUID(value.decode() if isinstance(value,bytes) else str(value))) +def timed(callback,repeat=1): + samples=[];value=None + for _ in range(repeat): + started=time.perf_counter();value=callback();samples.append(time.perf_counter()-started) + return value,{'samples_seconds':samples,'median_seconds':statistics.median(samples),'maximum_seconds':max(samples)} +def count_shapes(value): + if isinstance(value,list):return [len(value),[count_shapes(item) for item in value]] + return type(value).__name__ + + +def main(): + parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--manifest',type=Path,required=True) + parser.add_argument('--block-uuid',required=True);parser.add_argument('--output',type=Path,required=True);args=parser.parse_args() + if args.output.exists():parser.error('Choose an unused receipt') + modules=(objects,disk_module,projection_module);hashes=lambda:{module.__name__:sha(module.__file__) for module in modules} + report={'scope':__doc__,'source_hashes_before':hashes(),'probe_sha256':sha(__file__),'cases':[],'release_ready':False, + 'started_at':dt.datetime.now(dt.timezone.utc).isoformat()} + temporary=Path(tempfile.mkdtemp(prefix='rieke-real-metadata-oracle-')).resolve();index=None + stopping=threading.Event();phase=['input_verification'];peaks={} + def sample_storage(): + while not stopping.is_set(): + apparent=allocated=files=0 + for path in temporary.rglob('*'): + try: + if path.is_file() and not path.is_symlink(): + stat=path.stat();apparent+=stat.st_size;allocated+=stat.st_blocks*512;files+=1 + except FileNotFoundError:pass + value=peaks.setdefault(phase[0],{'apparent_bytes':0,'allocated_bytes':0,'files':0,'samples':0}) + for field,current in [('apparent_bytes',apparent),('allocated_bytes',allocated),('files',files)]:value[field]=max(value[field],current) + value['samples']+=1;stopping.wait(.02) + monitor=threading.Thread(target=sample_storage,daemon=True);monitor.start() + def check(name,passed,**detail): + report['cases'].append({'name':name,'passed':bool(passed),**detail});print(json.dumps(report['cases'][-1]),flush=True) + if not passed:raise AssertionError(name) + try: + manifest=json.loads(args.manifest.read_text());metadata_path=Path(manifest['metadata_path']);h5_path=Path(manifest['source_path']) + inputs={str(path):signature(path) for path in (args.manifest,metadata_path,h5_path)} + check('metadata_matches_imported_sha256',sha(metadata_path)==manifest['metadata_sha256']) + source_sha,report['source_hash_verification']=timed(lambda:sha(h5_path)) + check('physical_recording_matches_imported_sha256',source_sha==manifest['source_sha256']) + document=json.loads(metadata_path.read_text());selected=[] + for animal in document['animals']: + for preparation in animal['preparations']: + for cell in preparation['cells']: + for group in cell['epoch_groups']: + for block in group['epoch_blocks']: + if block['uuid']==args.block_uuid:selected.append((cell,group,block)) + check('block_identity_is_unique_in_source',len(selected)==1) + cell,group,block=selected[0];rows={};details={};fingerprints={};frames=block['properties']['frameTimesMs'] + expected_frames_sha=hashlib.sha256(raw(frames)).hexdigest();expected_shape_sha=hashlib.sha256(raw(count_shapes(frames))).hexdigest() + with h5py.File(h5_path,'r') as h5: + for epoch in block['epochs']: + streams=[] + for kind in ('responses','stimuli'): + for device,stream in epoch.get(kind,{}).items(): + handle=h5[stream['h5path']];owner=handle.parent.parent;ancestor=owner.parent.parent + assert identity(handle.attrs['uuid'])==stream['uuid'] and identity(owner.attrs['uuid'])==epoch['uuid'] and identity(ancestor.attrs['uuid'])==block['uuid'] + data=handle.get('data');units=None + if kind=='responses' and data is not None and len(data): + unit=data[0]['units'];units=unit.decode() if isinstance(unit,bytes) else str(unit) + streams.append({'uuid':stream['uuid'],'device':device,'kind':kind,'sample_rate':stream.get('sampleRate'), + 'sample_rate_units':stream.get('sampleRateUnits'),'sample_count':len(data) if data is not None else None, + 'units':units,'h5_path':stream['h5path'],'data_path':data.name if data is not None else None}) + duration=max([item['sample_count']/item['sample_rate'] for item in streams if item['kind']=='responses' and item['sample_rate'] and item['sample_count'] is not None],default=0) + row={'epoch_uuid':epoch['uuid'],'cell_uuid':cell['uuid'],'cell_label':cell['label'],'cell_type':cell.get('type'), + 'date':date(epoch['start_time']),'start_time':epoch['start_time'],'group_uuid':group['uuid'],'group_label':group.get('label'), + 'block_uuid':block['uuid'],'block_start_time':block.get('start_time'),'block_end_time':block.get('end_time'), + 'protocol_name':block['protocolID'],'duration_seconds':duration,'streams':streams,'source_sha256':source_sha, + 'metadata_hash':hashlib.sha256(json.dumps(epoch,sort_keys=True).encode()).hexdigest()} + detail={'parameters':epoch.get('parameters',{}),'properties':epoch.get('properties',{}),'attributes':epoch.get('attributes',{}), + 'metadata':{'cell':{key:value for key,value in cell.items() if key!='epoch_groups'}, + 'group':{key:value for key,value in group.items() if key!='epoch_blocks'}, + 'block':{key:value for key,value in block.items() if key!='epochs'},'epoch':epoch}} + rows[epoch['uuid']]=row;details[epoch['uuid']]=detail + fingerprints[epoch['uuid']]=hashlib.sha256(json.dumps({'epoch':detail,'source_sha256':source_sha},sort_keys=True,allow_nan=False).encode()).hexdigest() + check('physical_stream_parent_ownership_matches_every_selected_epoch',True,epochs=len(rows),streams=sum(len(row['streams']) for row in rows.values())) + report['fixture']={'metadata_path':str(metadata_path),'source_path':str(h5_path),'source_sha256':source_sha, + 'source_bytes':h5_path.stat().st_size,'metadata_bytes':metadata_path.stat().st_size,'block_uuid':block['uuid'],'epochs':len(rows), + 'frame_times_outer_count':len(frames),'frame_times_json_bytes':len(json.dumps(frames).encode()),'frame_times_canonical_bytes':len(raw(frames)), + 'frame_times_sha256':expected_frames_sha,'frame_times_shape_sha256':expected_shape_sha} + source={'source_sha256':source_sha,'filename':h5_path.name,'source_path':str(h5_path),'experiment_uuid':document['uuid'], + 'metadata':{key:value for key,value in document.items() if key!='animals'}} + cells={cell['uuid']:{'cell_uuid':cell['uuid'],'label':cell['label'],'cell_type':cell.get('type'),'date':date(cell['start_time']),'start_time':cell['start_time']}} + projection={'rows':rows,'details':details,'cells':cells,'source':source,'fingerprints':fingerprints} + expected={key:hashlib.sha256(raw(value)).hexdigest() for key,value in details.items()} + phase[0]='index_build' + index,report['index_build']=timed(lambda:DiskMetadataIndex.build(temporary/'normalized'/'index.sqlite',rows,details,[source],'physical-source-normalization',manifest['project_uuid'])) + phase[0]='index_validation' + check('index_row_ownership_and_fingerprints_exact',index.rows()==rows and index.fingerprints()==fingerprints) + def verify_details(mapping): + for key in rows: + actual=mapping[key] + assert hashlib.sha256(raw(actual)).hexdigest()==expected[key] + array=actual['metadata']['block']['properties']['frameTimesMs'] + assert hashlib.sha256(raw(array)).hexdigest()==expected_frames_sha + assert hashlib.sha256(raw(count_shapes(array))).hexdigest()==expected_shape_sha + return True + _,report['all_index_details_read']=timed(lambda:verify_details(index.details)) + check('all_index_details_arrays_shapes_and_types_exact',True,decoded_ancestors=index._metadata_decoder.object_decodes) + check('one_block_decoded_once_across_all_epochs',index._metadata_decoder.object_decodes==3) + first=next(iter(rows));changed=index.details[first];changed['metadata']['block']['properties']['frameTimesMs'][0].append(-999) + check('mutating_public_index_detail_does_not_change_next_result',hashlib.sha256(raw(index.details[first])).hexdigest()==expected[first]) + _,report['warm_single_detail_read']=timed(lambda:index.details[first],repeat=20) + for lazy in (False,True): + value,timing=timed(lambda:index.source_projection(source_sha,lazy_details=lazy));report['source_projection_'+('lazy' if lazy else 'eager')]=timing + check('source_projection_'+('lazy' if lazy else 'eager')+'_preserves_exact_details',verify_details(value['details']) and value['fingerprints']==fingerprints) + phase[0]='duplicated_index_comparison';baseline=temporary/'duplicated-detail-comparison.sqlite' + with sqlite3.connect(index.path.as_uri()+'?mode=ro',uri=True) as source_db: + with sqlite3.connect(baseline) as target: + source_db.backup(target) + target.executemany('UPDATE epochs SET detail_blob=? WHERE epoch_uuid=?',[(zlib.compress(raw(value)),key) for key,value in details.items()]) + target.execute('DROP TABLE metadata_objects');target.commit();target.execute('VACUUM') + report['storage']={'normalized_index':storage(index.path),'duplicated_detail_index_comparison':storage(baseline)} + with sqlite3.connect(index.path.as_uri()+'?mode=ro',uri=True) as database: + report['index_sql_bytes']={'objects':database.execute('SELECT COUNT(*),SUM(LENGTH(payload)) FROM metadata_objects').fetchone(), + 'per_epoch_detail_blobs':database.execute('SELECT SUM(LENGTH(detail_blob)) FROM epochs').fetchone()[0]} + with sqlite3.connect(baseline) as database: + report['duplicated_detail_blob_bytes']=database.execute('SELECT SUM(LENGTH(detail_blob)) FROM epochs').fetchone()[0] + cache=ProjectionCache(temporary/'projections');key={'source_sha256':source_sha,'metadata_sha256':manifest['metadata_sha256'],'oracle':'physical-block'} + phase[0]='projection_write' + _,report['projection_write']=timed(lambda:cache.write(key,projection)) + phase[0]='projection_read_and_validation';loaded,report['projection_read']=timed(lambda:cache.read(key)) + check('projection_cache_preserves_every_detail_and_fingerprint',loaded is not None and verify_details(loaded['details']) and loaded['fingerprints']==fingerprints and loaded['rows']==rows) + loaded['details'][first]['metadata']['block']['properties']['frameTimesMs'][0].append(-999) + reread=cache.read(key);check('projection_public_mutation_does_not_change_stored_result',hashlib.sha256(raw(reread['details'][first])).hexdigest()==expected[first]) + report['storage']['normalized_projection']=storage(temporary/'projections') + phase[0]='duplicated_projection_comparison';old=temporary/'duplicated-projection-comparison.json.zlib' + old.write_bytes(zlib.compress(json.dumps({'version':1,'key_hash':checksum(key),'projection':projection},allow_nan=False,separators=(',',':')).encode(),level=1)) + report['storage']['duplicated_projection_comparison']=storage(old) + report['storage']['all_temporary_artifacts']=storage(temporary) + check('all_original_input_signatures_unchanged',all(signature(path)==before for path,before in inputs.items())) + report['source_hashes_after']=hashes();report['source_unchanged']=report['source_hashes_before']==report['source_hashes_after'];report['peak_rss_bytes']=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + except Exception as error:report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()};print(traceback.format_exc(),flush=True) + finally: + stopping.set();monitor.join(timeout=2) + report['peak_temporary_storage_by_phase']=peaks + report['peak_storage_sampling_note']='20ms sampling of disposable files; each phase includes already-built artifacts. Values are observed lower bounds on instantaneous staging peaks.' + report['finished_at']=dt.datetime.now(dt.timezone.utc).isoformat() + if index is not None:index.close() + shutil.rmtree(temporary);report['temporary_artifacts_removed']=not temporary.exists() + report['passed']=not report.get('error') and report.get('source_unchanged',False) and all(case['passed'] for case in report['cases']) and report['temporary_artifacts_removed'] + args.output.write_text(json.dumps(report,indent=2)+'\n') + return int(not report['passed']) + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/mounted_scientist_workflow.mjs b/docs/dev/scale-audit-2026-09-29/mounted_scientist_workflow.mjs new file mode 100644 index 0000000..5c25954 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/mounted_scientist_workflow.mjs @@ -0,0 +1,45 @@ +// Controlled transport-delay experiment, not browser paint or native HTTP timing. +import {createWorkflowHarness} from '../../../workspace-app/src/test-support/workflowHarness.js'; +import {writeFile,readFile} from 'node:fs/promises'; +import {createHash} from 'node:crypto'; +import {resolve} from 'node:path'; +const destination=process.argv[2]; +if(!destination)throw Error('Provide a new JSON receipt path and optional immutable baseline src directory'); +const root=resolve(import.meta.dirname,'../../..'); +const baselineRoot=resolve(process.argv[3]||process.env.RIEKE_WORKFLOW_BASELINE_ROOT||resolve(root,'docs/dev/scale-audit-2026-09-29/frozen-100000-dense-recovery/snapshot/workspace-app/src')); +const baselineFiles=['App.jsx','components/Inspector.jsx','components/AnnotationTags.jsx']; +const files=['workspace-app/src/App.jsx','workspace-app/src/components/Inspector.jsx','workspace-app/src/components/AnnotationTags.jsx','workspace-app/src/useWorkspaceChanges.js','workspace-app/src/epochBrowserSource.js','workspace-app/src/test-support/workflowHarness.js','workspace-app/src/api.js','workspace-app/src/resourceRequest.js','workspace-app/src/resourceCache.js','workspace-app/src/annotationTags.js','workspace-app/src/curationSelection.js','workspace-app/src/epochSelection.js','workspace-app/src/inspectionCellTree.js','workspace-app/src/components/InspectionCellTree.jsx','workspace-app/src/components/EpochTags.jsx','workspace-app/src/components/ProtocolViewFilter.jsx','workspace-app/src/protocolViewFilter.js','workspace-app/src/components/Common.jsx','workspace-app/src/useImportMonitor.js','workspace-app/package-lock.json']; +const hash=async path=>createHash('sha256').update(await readFile(path)).digest('hex'); +const hashes=async()=>Object.fromEntries(await Promise.all(files.map(async file=>[file,await hash(resolve(root,file))]))); +const baselineHashes=async()=>Object.fromEntries(await Promise.all(baselineFiles.map(async file=>[file,await hash(resolve(baselineRoot,file))]))); +const report={baseline_root:baselineRoot,baseline_components_before:await baselineHashes(),baseline_description:'Prior App/Inspector/AnnotationTags flow components with current harness and support modules; not a full historical application build.',scope:'Mounted React product request/authority lifecycle with simulated transport; no browser rendering, native database, H5 trace or real-scientist latency claim.',started_at:new Date().toISOString(),before:await hashes(),transport_ms:{save:25,overview:120,page:40,metadata_fields:40,focused_epoch:20,other:10},cases:[]}; +const predicate=name=>({tag_predicate:JSON.stringify({all:[{field:'annotations/effective/tags',operator:'contains',value:name},{not:{field:'annotations/epoch/tags',operator:'contains',value:'excluded'}}]})}); +const delay=record=>record.method==='POST'?25:/^\/(overview|projects|protocol-suggestions|protocols\/[^/?]+)(?:\?|$)/.test(record.path)?120:record.path.includes('/epochs?')||record.path.includes('/tree-fields')||record.path==='/metadata/fields'?40:record.path.startsWith('/epochs/')?20:10; +const serialize=(records,start)=>records.map(record=>({...record,started_ms:record.started-start,completed_ms:record.completed-start,started:undefined,completed:undefined})); +for(const total of [500,1000,5000,100000])for(const baseline of [true,false]){ + const h=await createWorkflowHarness({total,baseline,delay,baselineRoot}); + try{ + await h.mount();await h.waitFor(()=>{try{return h.viewer.epoch&&!h.root.findByProps({'aria-label':'Tag this epoch'}).props.disabled;}catch{return false;}}); + await h.settle(260); + const item={epochs:total,implementation:baseline?'prior flow components with current harness/support':'current flow components with current harness/support',operations:[],initial_inspector_mounts:h.fixture.mounts}; + let mark=h.fixture.requests.length,start=performance.now(); + await h.act(()=>h.root.findByProps({'aria-label':'Tag this epoch'}).props.onChange({target:{value:'workflow saved tag'}})); + await h.act(()=>h.root.findByProps({'aria-label':'Tag this epoch'}).parent.props.onSubmit({preventDefault(){}})); + await h.waitFor(()=>{try{return h.viewer.epoch?.annotations.epoch_tags.some(tag=>tag.tag==='workflow saved tag')&&!h.root.findByProps({'aria-label':'Tag this epoch'}).props.disabled;}catch{return false;}}); + item.operations.push({action:'save shared epoch tag then current authority editable',controlled_completion_ms:performance.now()-start,requests:serialize(h.fixture.requests.slice(mark),start)}); + await h.settle(260); + for(const name of ['A','B','A']){ + mark=h.fixture.requests.length;start=performance.now(); + await h.act(()=>h.viewer.onViewFilters(predicate(name))); + await h.waitFor(()=>{try{return !h.viewer.navigation.loading&&h.viewer.navigation.total===total/2;}catch{return false;}}); + item.operations.push({action:`filter ${name}`,controlled_completion_ms:performance.now()-start,requests:serialize(h.fixture.requests.slice(mark),start)}); + await h.settle(260); + } + item.final_inspector_mounts=h.fixture.mounts;item.inspector_unmounts=h.fixture.unmounts; + report.cases.push(item); + console.log(JSON.stringify({epochs:total,baseline,mounts:item.final_inspector_mounts,operations:item.operations.map(operation=>({action:operation.action,requests:operation.requests.length,ms:Math.round(operation.controlled_completion_ms)}))})); + }finally{await h.close();} +} +report.after=await hashes();report.baseline_components_after=await baselineHashes();report.source_unchanged=JSON.stringify(report.before)===JSON.stringify(report.after)&&JSON.stringify(report.baseline_components_before)===JSON.stringify(report.baseline_components_after);report.finished_at=new Date().toISOString(); +report.limitations=['The renderer mounts actual App/Protocol/Inspector/tag/filter/cell-tree code but replaces layout/trace drawing and unrelated screens.','Synthetic transport delay is controlled; timing differences show dependency order and request fanout, not production p95.','All four declared dataset sizes create bounded page responses and at most one cell summary per500epochs; no raw100k-row React view is mounted.','Open tree/column branches and actual H5 trace latency are outside this mounted collapsed-cell-list measurement.','Native workflow receipts separately measure server operations; neither receipt alone measures browser paint.']; +await writeFile(destination,JSON.stringify(report,null,2)+'\n',{flag:'wx'}); diff --git a/docs/dev/scale-audit-2026-09-29/mysql_generation_primitives.py b/docs/dev/scale-audit-2026-09-29/mysql_generation_primitives.py new file mode 100644 index 0000000..ad56ffa --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/mysql_generation_primitives.py @@ -0,0 +1,147 @@ +"""Probe actual MySQL generation/DDL semantics in an owned disposable server. + +This validates native primitives, not the application's forthcoming authority +module. Never accepts an existing project or database address. +""" +import argparse +import json +import os +from pathlib import Path +import shutil +import tempfile +import time + +import pymysql +from workspace_projects import create_project +from workspace_native_mysql import ensure_native_database,stop_native_database,connection_parameters + +DB='rieke_generation_probe' + + +def main(): + parser=argparse.ArgumentParser(description=__doc__) + parser.add_argument('--output',type=Path,required=True) + parser.add_argument('--recreate-attempts',type=int,default=100) + args=parser.parse_args() + if args.output.exists():parser.error('Choose an unused output file') + report={'scope':'Disposable native SQL primitive probes; not application authority/cache certification','cases':[]} + root=Path(tempfile.mkdtemp(prefix='rieke-generation-primitives-'));project=None;connection=None + def emit(name,**values): + record={'name':name,**values};report['cases'].append(record);print(json.dumps(record,default=str),flush=True) + try: + project=Path(create_project(root/'projects','Generation primitives')['path']) + ensure_native_database(project) + connection=pymysql.connect(**connection_parameters(project),autocommit=True) + def sql(statement,args=None): + with connection.cursor() as cursor: + cursor.execute(statement,args);return cursor.fetchall() + report['mysql_version']=sql('SELECT VERSION()')[0][0] + sql(f'CREATE DATABASE `{DB}`') + source_sql=f'''CREATE TABLE `{DB}`.`source` ( + project_uuid VARCHAR(36) NOT NULL, protocol_uuid VARCHAR(36) NOT NULL, + epoch_uuid VARCHAR(36) NOT NULL, tags JSON NOT NULL, revision INT UNSIGNED NOT NULL, + PRIMARY KEY(project_uuid,protocol_uuid,epoch_uuid)) ENGINE=InnoDB''' + clock_sql=f'''CREATE TABLE `{DB}`.`clock` ( + project_uuid VARCHAR(36) NOT NULL, protocol_uuid VARCHAR(36) NOT NULL, + generation BIGINT UNSIGNED NOT NULL, PRIMARY KEY(project_uuid,protocol_uuid)) ENGINE=InnoDB''' + sql(source_sql);sql(clock_sql) + def bump(prefix): + return f'INSERT INTO `{DB}`.`clock` VALUES ({prefix}.project_uuid,{prefix}.protocol_uuid,1) ON DUPLICATE KEY UPDATE generation=generation+1;' + definitions={ + 'insert':f'CREATE TRIGGER `{DB}`.`bump_insert` AFTER INSERT ON `{DB}`.`source` FOR EACH ROW BEGIN {bump("NEW")} END', + 'update':f'CREATE TRIGGER `{DB}`.`bump_update` AFTER UPDATE ON `{DB}`.`source` FOR EACH ROW BEGIN {bump("OLD")} IF OLD.project_uuid<>NEW.project_uuid OR OLD.protocol_uuid<>NEW.protocol_uuid THEN {bump("NEW")} END IF; END', + 'delete':f'CREATE TRIGGER `{DB}`.`bump_delete` AFTER DELETE ON `{DB}`.`source` FOR EACH ROW BEGIN {bump("OLD")} END', + } + for definition in definitions.values():sql(definition) + def ddl_status(conn=None): + with (conn or connection).cursor() as cursor: + cursor.execute("SHOW GLOBAL STATUS WHERE Variable_name IN ('Com_create_trigger','Com_drop_trigger','Com_create_table','Com_drop_table','Com_alter_table','Com_rename_table','Com_truncate','Com_create_db','Com_drop_db')") + return {name:int(value) for name,value in cursor.fetchall()} + def clock():return sql(f'SELECT project_uuid,protocol_uuid,generation FROM `{DB}`.`clock` ORDER BY project_uuid,protocol_uuid') + def table_id(table):return sql('SELECT TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME=%s',(DB+'/'+table,))[0][0] + def triggers():return sql('SELECT TRIGGER_NAME,EVENT_MANIPULATION,ACTION_TIMING,ACTION_STATEMENT,CREATED,DEFINER FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s ORDER BY TRIGGER_NAME',(DB,)) + def source():return sql(f'SELECT project_uuid,protocol_uuid,epoch_uuid,tags,revision FROM `{DB}`.`source` ORDER BY project_uuid,protocol_uuid,epoch_uuid') + def insert():sql(f'INSERT INTO `{DB}`.`source` VALUES (%s,%s,%s,%s,1)',('project-A','protocol-A','epoch-A',json.dumps(['QC','tag-A']))) + insert();emit('insert',clock=clock(),source=source()) + previous=clock();sql(f'UPDATE `{DB}`.`source` SET tags=%s',(json.dumps(['QC','tag-B']),)) + emit('same_revision_update',clock_before=previous,clock_after=clock(),source=source()) + previous=clock();sql(f'REPLACE INTO `{DB}`.`source` VALUES (%s,%s,%s,%s,1)',('project-A','protocol-A','epoch-A',json.dumps(['QC','tag-C']))) + emit('replace',clock_before=previous,clock_after=clock()) + previous=clock();sql(f'UPDATE `{DB}`.`source` SET project_uuid=%s,protocol_uuid=%s',('project-B','protocol-B')) + emit('project_and_protocol_move',clock_before=previous,clock_after=clock()) + previous=clock();before=source();connection.begin();sql(f'UPDATE `{DB}`.`source` SET tags=%s',(json.dumps(['rollback']),));inside=clock();connection.rollback() + emit('rollback',clock_before=previous,clock_inside=inside,clock_after=clock(),source_preserved=source()==before) + previous=clock();sql(f'DELETE FROM `{DB}`.`source`');emit('delete_last_row',clock_before=previous,clock_after=clock(),source=source()) + insert();previous=clock();old_table_id=table_id('source');old_triggers=triggers() + sql(f'TRUNCATE TABLE `{DB}`.`source`') + emit('truncate_source',clock_unchanged=clock()==previous,table_id_before=old_table_id,table_id_after=table_id('source'),triggers_unchanged=triggers()==old_triggers) + insert();previous=clock();old_table_id=table_id('source') + sql(f'DROP TABLE `{DB}`.`source`');sql(source_sql) + for definition in definitions.values():sql(definition) + emit('drop_recreate_source',clock_unchanged=clock()==previous,table_id_before=old_table_id,table_id_after=table_id('source')) + insert() + # The exposed CREATED timestamp may be too coarse to establish that + # coverage never disappeared between reads, even with identical bodies. + collision=None;durations=[] + for attempt in range(args.recreate_attempts): + sql(f'DROP TRIGGER `{DB}`.`bump_update`');sql(definitions['update']) + before=triggers();previous=clock();rows_before=source();ddl_before=ddl_status();tick=time.perf_counter() + sql(f'DROP TRIGGER `{DB}`.`bump_update`') + sql(f'UPDATE `{DB}`.`source` SET tags=%s',(json.dumps(['QC',f'untracked-{attempt}']),)) + sql(definitions['update']);elapsed=time.perf_counter()-tick;durations.append(elapsed) + after=triggers() + if before==after: + collision={'attempt':attempt+1,'seconds':elapsed,'trigger_signature_unchanged':True, + 'source_table_id':table_id('source'),'clock_unchanged':clock()==previous, + 'source_changed':source()!=rows_before,'trigger_metadata':after, + 'ddl_before':ddl_before,'ddl_after':ddl_status()} + break + emit('drop_recreate_trigger_coverage_gap',attempts=len(durations),collision=collision, + minimum_seconds=min(durations) if durations else None, + conclusion='A matching metadata signature hid a missed write' if collision else 'No metadata-signature collision observed; absence is not a proof of continuous trigger coverage') + before=ddl_status();sql('FLUSH STATUS');emit('flush_status_same_connection',before=before,after=ddl_status()) + other=pymysql.connect(**connection_parameters(project),autocommit=True) + try: + before=ddl_status() + with other.cursor() as cursor:cursor.execute('FLUSH STATUS') + emit('flush_status_other_connection',before=before,after=ddl_status()) + before=ddl_status() + with other.cursor() as cursor: + cursor.execute(f'CREATE TABLE `{DB}`.`scratch` (id INT PRIMARY KEY) ENGINE=InnoDB') + cursor.execute(f'DROP TABLE `{DB}`.`scratch`') + live=ddl_status() + finally:other.close() + emit('other_connection_disconnect',before=before,while_connected=live,after_disconnect=ddl_status()) + for kind,statement in [('drop_trigger',f'DROP TRIGGER `{DB}`.`bump_update`'),('create_trigger',definitions['update']),('alter_table',f'ALTER TABLE `{DB}`.`source` ADD COLUMN probe_column INT NULL')]: + before=ddl_status();error=None;prepared=False + try: + sql('PREPARE ddl_probe FROM %s',(statement,));prepared=True;sql('EXECUTE ddl_probe') + except Exception as exc:error={'type':type(exc).__name__,'message':str(exc)} + finally: + if prepared:sql('DEALLOCATE PREPARE ddl_probe') + emit('prepared_'+kind,before=before,after=ddl_status(),error=error) + if not any(row[0]=='bump_update' for row in triggers()):sql(definitions['update']) + old=table_id('clock');sql(f'TRUNCATE TABLE `{DB}`.`clock`');emit('truncate_generation_table',table_id_before=old,table_id_after=table_id('clock'),clock=clock(),source_count=len(source())) + sql(f'UPDATE `{DB}`.`source` SET tags=%s',(json.dumps(['QC','after-clock-reset']),)) + emit('write_after_missing_generation_row',clock=clock()) + sql(f'DELETE FROM `{DB}`.`clock`');emit('delete_generation_row',table_id=table_id('clock'),clock=clock(),source_count=len(source())) + report['trigger_created_column']=sql('SELECT DATA_TYPE,DATETIME_PRECISION FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=%s AND TABLE_NAME=%s AND COLUMN_NAME=%s',('information_schema','TRIGGERS','CREATED')) + except Exception as error: + import traceback + report['error']={'type':type(error).__name__,'message':str(error),'traceback':traceback.format_exc()} + print(traceback.format_exc(),flush=True) + finally: + if connection is not None:connection.close() + clean=False + if project is not None: + try:clean=stop_native_database(project) + except Exception as error:report['shutdown_error']=str(error) + report['clean_native_shutdown']=clean + if clean:shutil.rmtree(root);report['temporary_project_removed']=True + else:report['temporary_project_preserved']=str(root) + report['release_ready']=False + args.output.write_text(json.dumps(report,indent=2,default=str)+'\n') + return int(bool(report.get('error')) or not clean) + + +if __name__=='__main__':raise SystemExit(main()) diff --git a/docs/dev/scale-audit-2026-09-29/mysql_inflight_ddl_probe.py b/docs/dev/scale-audit-2026-09-29/mysql_inflight_ddl_probe.py new file mode 100644 index 0000000..c2400b0 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/mysql_inflight_ddl_probe.py @@ -0,0 +1,112 @@ +"""Test counter and metadata visibility while real trigger DDL waits on MDL.""" +import argparse +import json +from pathlib import Path +import shutil +import struct +import tempfile +import threading +import time +import traceback + +import pymysql +from workspace_projects import create_project +from workspace_native_mysql import ensure_native_database,stop_native_database,connection_parameters + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--output',type=Path,required=True);args=ap.parse_args() + if args.output.exists():ap.error('Choose unused receipt') + root=Path(tempfile.mkdtemp(prefix='rieke-inflight-ddl-'));project=None;clients=[];threads=[];report={'cases':[],'release_ready':False} + try: + project=Path(create_project(root/'projects','Inflight DDL probe')['path']);ensure_native_database(project) + def client(): + conn=pymysql.connect(**connection_parameters(project),autocommit=True);clients.append(conn);return conn + primary=client();holder=client();dropper=client();writer=client();creator=client();inspector=client() + def sql(conn,statement,args=None): + with conn.cursor() as cur:cur.execute(statement,args);return cur.fetchall() + report['mysql_version']=sql(primary,'SELECT VERSION()')[0][0] + sql(primary,'CREATE DATABASE ddl_probe');sql(primary,'CREATE TABLE ddl_probe.source(id INT PRIMARY KEY,value INT) ENGINE=InnoDB');sql(primary,'CREATE TABLE ddl_probe.clock(value INT) ENGINE=InnoDB');sql(primary,'INSERT INTO ddl_probe.clock VALUES (0)') + sql(primary,'INSERT INTO ddl_probe.source VALUES (1,0)') + definition='CREATE TRIGGER ddl_probe.tracked AFTER UPDATE ON ddl_probe.source FOR EACH ROW UPDATE ddl_probe.clock SET value=value+1' + sql(primary,definition) + def counters():return dict(sql(primary,"SHOW GLOBAL STATUS WHERE Variable_name IN ('Com_create_trigger','Com_drop_trigger')")) + report['counters_before']=counters() + holder.begin();sql(holder,'SELECT * FROM ddl_probe.source') + events={} + def background(name,conn,statement): + def run(): + start=time.perf_counter();events[name]={'started':start} + try:events[name]['rows']=statement(conn) if callable(statement) else sql(conn,statement) + except Exception as error:events[name]['error']=str(error) + finally:events[name]['finished']=time.perf_counter();events[name]['seconds']=events[name]['finished']-start + thread=threading.Thread(target=run,daemon=True);threads.append(thread);thread.start() + background('drop',dropper,'DROP TRIGGER ddl_probe.tracked');time.sleep(.05) + background('write',writer,'UPDATE ddl_probe.source SET value=99');time.sleep(.05) + background('create',creator,definition);time.sleep(.05) + report['counters_while_all_blocked']=counters() + report['pending_mdl']=sql(primary,"SELECT OBJECT_TYPE,OBJECT_SCHEMA,OBJECT_NAME,LOCK_TYPE,LOCK_STATUS FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA='ddl_probe'") + background('inspect',inspector,"SELECT TRIGGER_NAME,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA='ddl_probe'") + time.sleep(.15) + report['inspection_finished_before_release']='finished' in events['inspect'] + report['events_before_release']={name:dict(values) for name,values in events.items()} + report['active_statement_instrumentation']=sql(primary,"SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME='events_statements_current'") + report['active_ddl_statements']=sql(primary,"SELECT EVENT_NAME,END_EVENT_ID,SQL_TEXT FROM performance_schema.events_statements_current WHERE EVENT_NAME IN ('statement/sql/drop_trigger','statement/sql/create_trigger') AND END_EVENT_ID IS NULL") + holder.rollback() + for thread in threads:thread.join(timeout=5) + report['events']=events;report['counters_after']=counters();report['final_source']=sql(primary,'SELECT * FROM ddl_probe.source');report['final_clock']=sql(primary,'SELECT * FROM ddl_probe.clock') + report['all_threads_finished']=all(not thread.is_alive() for thread in threads) + # PREPARE exposes the executing underlying DDL instrument, rather than + # hiding it behind only a generic EXECUTE event. + holder.begin();sql(holder,'SELECT * FROM ddl_probe.source') + sql(dropper,"PREPARE pending_alter FROM 'ALTER TABLE ddl_probe.source ADD COLUMN extra_column INT NULL'") + background('prepared_alter',dropper,'EXECUTE pending_alter');time.sleep(.1) + report['prepared_alter_active']=sql(primary,"SELECT EVENT_NAME,END_EVENT_ID,SQL_TEXT FROM performance_schema.events_statements_current WHERE END_EVENT_ID IS NULL") + report['instrumented_foreground']=sql(primary,"SELECT INSTRUMENTED,COUNT(*) FROM performance_schema.threads WHERE TYPE='FOREGROUND' GROUP BY INSTRUMENTED") + report['required_consumers']=sql(primary,"SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('global_instrumentation','thread_instrumentation','events_statements_current')") + report['ddl_instruments']=sql(primary,"SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN ('statement/sql/create_trigger','statement/sql/drop_trigger','statement/sql/create_table','statement/sql/drop_table','statement/sql/alter_table','statement/sql/rename_table','statement/sql/truncate','statement/sql/create_db','statement/sql/drop_db')") + report['executor_instruments']=sql(primary,"SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME LIKE '%Execute%' OR NAME LIKE '%call%' OR NAME LIKE '%event%' OR NAME LIKE '%tablespace%'") + report['tablespace_counters']=sql(primary,"SHOW GLOBAL STATUS WHERE Variable_name LIKE 'Com%tablespace%'") + report['scheduler_settings']=sql(primary,'SELECT @@event_scheduler,@@log_bin') + report['performance_schema_losses']=sql(primary,"SHOW GLOBAL STATUS WHERE Variable_name LIKE 'Performance_schema%lost'") + report['uninstrumented_threads']=sql(primary,"SELECT NAME,TYPE,PROCESSLIST_USER FROM performance_schema.threads WHERE INSTRUMENTED='NO'") + report['actual_connection_count']=sql(primary,"SHOW GLOBAL STATUS WHERE Variable_name IN ('Connections','Threads_connected')") + report['instrumented_connection_population']=sql(primary,"SELECT NAME,PROCESSLIST_ID,PROCESSLIST_USER,PROCESSLIST_COMMAND,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='FOREGROUND' AND PROCESSLIST_ID IS NOT NULL") + holder.rollback() + for thread in threads:thread.join(timeout=5) + report['all_threads_finished']=all(not thread.is_alive() for thread in threads) + holder.begin();sql(holder,'SELECT * FROM ddl_probe.source') + from pymysql.constants import COMMAND + dropper._execute_command(COMMAND.COM_STMT_PREPARE,'ALTER TABLE ddl_probe.source ADD COLUMN binary_column INT NULL') + packet=dropper._read_packet();packet.check_error();packet.read_uint8();statement_id=packet.read_uint32() + columns=packet.read_uint16();parameters=packet.read_uint16() + if columns or parameters:raise AssertionError('Unexpected parameterless DDL preparation metadata') + def binary_execute(conn): + conn._execute_command(COMMAND.COM_STMT_EXECUTE,struct.pack('=%s AND fold_key<%s", + "seconds": 0.0001492909505032003, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00015729200094938278, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.0001496669719927013, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00015233299927785993, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013812503311783075, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013883301289752126, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00019345799228176475, + "result_rows": 3 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.00014100002590566874, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.00015254097525030375, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00016245798906311393, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.00017329101683571935, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00016587501158937812, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014037505025044084, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001366669894196093, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00019987503765150905, + "result_rows": 3 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0002447500010021031, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "seconds": 0.00015116599388420582, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00016816600691527128, + "result_rows": 12 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00023812497965991497, + "result_rows": 24 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014874996850267053, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00017024995759129524, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00029045797418802977, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012725003762170672, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00020070798927918077, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001289580250158906, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013695796951651573, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012425001477822661, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012670899741351604, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011995801469311118, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011025002459064126, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011108402395620942, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001033750013448298, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011508399620652199, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011308299144729972, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014779099728912115, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011537497630342841, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010775000555440784, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011224998161196709, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010175001807510853, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010091596050187945, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010791700333356857, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013529200805351138, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011187494965270162, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00030766602139919996, + "result_rows": 12 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": "const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using index condition; Using filesort" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "38", + "ref": "const", + "rows": 41, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_rank", + "key": "by_rank", + "key_len": "38", + "ref": "const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 24, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 12, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "filter20_cpu_profile": { + "top_functions": [ + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 367, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.709000000000001e-06, + "cumulative_seconds": 0.299808417 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 178, + "function": "request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.5840000000000005e-06, + "cumulative_seconds": 0.29978295800000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1163, + "function": "get", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.167e-06, + "cumulative_seconds": 0.29894175 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/testing.py", + "line": 204, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.2415e-05, + "cumulative_seconds": 0.298935583 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1062, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.7080000000000005e-06, + "cumulative_seconds": 0.29864266700000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 984, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.876e-06, + "cumulative_seconds": 0.298629209 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1230, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.707e-06, + "cumulative_seconds": 0.298439083 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1529, + "function": "__call__", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.375000000000001e-06, + "cumulative_seconds": 0.298408708 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1479, + "function": "wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.4583e-05, + "cumulative_seconds": 0.298402333 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 904, + "function": "full_dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.332000000000001e-06, + "cumulative_seconds": 0.298125625 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 879, + "function": "dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.00010991700000000001, + "cumulative_seconds": 0.297899792 + }, + { + "file": "python/workspace_api.py", + "line": 716, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000116674, + "cumulative_seconds": 0.297783083 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 27, + "calls": 38, + "self_seconds": 3.0665e-05, + "cumulative_seconds": 0.14365666600000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 249, + "function": "native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.2001e-05, + "cumulative_seconds": 0.14359354100000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 268, + "function": "_native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.2542e-05, + "cumulative_seconds": 0.127715832 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 311, + "function": "native_context", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.6543000000000005e-05, + "cumulative_seconds": 0.127648709 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 207, + "function": "_metadata_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 0.006965624, + "cumulative_seconds": 0.12444129200000001 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 22, + "calls": 4058, + "self_seconds": 0.001259605, + "cumulative_seconds": 0.11774566800000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 212, + "function": "", + "primitive_calls": 18, + "calls": 18, + "self_seconds": 2.0916e-05, + "cumulative_seconds": 0.11746775000000001 + }, + { + "file": "python/workspace_service.py", + "line": 748, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000894459, + "cumulative_seconds": 0.11737054200000001 + }, + { + "file": "python/workspace_service.py", + "line": 778, + "function": "_epoch_page_identities", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.007612187, + "cumulative_seconds": 0.11643441700000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 55, + "function": "_epoch_query_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 0.08887966400000001, + "cumulative_seconds": 0.11188629200000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 261, + "function": "filter_epoch_ids", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.016227171000000002, + "cumulative_seconds": 0.08914675000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 141, + "function": "__exit__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 9.626e-06, + "cumulative_seconds": 0.07195900000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 132, + "function": "__enter__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 2.21e-06, + "cumulative_seconds": 0.07164325 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 8, + "function": "matching", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.045147576, + "cumulative_seconds": 0.066060375 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 358, + "function": "traced_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00021226300000000002, + "cumulative_seconds": 0.025589415 + }, + { + "file": "python/workspace_annotations.py", + "line": 295, + "function": "for_epochs", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.00012045400000000001, + "cumulative_seconds": 0.0255335 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 412, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00012195600000000001, + "cumulative_seconds": 0.024990334000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 402, + "function": "_execute_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000130289, + "cumulative_seconds": 0.0246865 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 150, + "function": "execute", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.9329e-05, + "cumulative_seconds": 0.024284916 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 332, + "function": "_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.950000000000001e-05, + "cumulative_seconds": 0.023814921000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 575, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.811600000000001e-05, + "cumulative_seconds": 0.023325748 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 535040, + "calls": 535040, + "self_seconds": 0.022528403000000002, + "cumulative_seconds": 0.022528403000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 851, + "function": "_read_query_result", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.7166e-05, + "cumulative_seconds": 0.022226916000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1288, + "function": "read", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.6334e-05, + "cumulative_seconds": 0.022138332 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 128, + "function": "deepcopy", + "primitive_calls": 78, + "calls": 17170, + "self_seconds": 0.009486142000000001, + "cumulative_seconds": 0.016137543 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 201, + "function": "_deepcopy_list", + "primitive_calls": 62, + "calls": 102, + "self_seconds": 0.000323195, + "cumulative_seconds": 0.016002293 + }, + { + "file": "python/workspace_state_generation.py", + "line": 101, + "function": "_rows", + "primitive_calls": 46, + "calls": 46, + "self_seconds": 5.5412000000000004e-05, + "cumulative_seconds": 0.015927913000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 197, + "function": "response_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.7125000000000002e-05, + "cumulative_seconds": 0.015823083 + }, + { + "file": "python/workspace_state_generation.py", + "line": 233, + "function": "_attest_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 6.5579e-05, + "cumulative_seconds": 0.015792167 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 227, + "function": "_deepcopy_dict", + "primitive_calls": 1242, + "calls": 1284, + "self_seconds": 0.0028571290000000004, + "cumulative_seconds": 0.014009929 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 763, + "function": "_read_packet", + "primitive_calls": 769, + "calls": 769, + "self_seconds": 0.001213818, + "cumulative_seconds": 0.013894895 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1370, + "function": "_read_result_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.137200000000001e-05, + "cumulative_seconds": 0.011831251000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 869, + "function": "to_dicts", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.9538e-05, + "cumulative_seconds": 0.011663040000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 813, + "function": "_read_bytes", + "primitive_calls": 1538, + "calls": 1538, + "self_seconds": 0.0005588720000000001, + "cumulative_seconds": 0.010801998 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 1538, + "calls": 1538, + "self_seconds": 0.000212718, + "cumulative_seconds": 0.010166722000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/socket.py", + "line": 704, + "function": "readinto", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 8.1743e-05, + "cumulative_seconds": 0.009954004 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1299, + "function": "recv_into", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 8.1827e-05, + "cumulative_seconds": 0.009832420000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1157, + "function": "read", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 4.7619000000000006e-05, + "cumulative_seconds": 0.00973996 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 0.009687419000000001, + "cumulative_seconds": 0.009687419000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 1231, + "function": "cursor", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 1.8547e-05, + "cumulative_seconds": 0.009504543 + }, + { + "file": "python/workspace_service.py", + "line": 845, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.009479084, + "cumulative_seconds": 0.009479084 + }, + { + "file": "python/workspace_service.py", + "line": 797, + "function": "", + "primitive_calls": 100001, + "calls": 100001, + "self_seconds": 0.009434314000000001, + "cumulative_seconds": 0.009434314000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 34, + "function": "_exact_equal", + "primitive_calls": 22, + "calls": 14072, + "self_seconds": 0.0035740480000000002, + "cumulative_seconds": 0.009078833000000001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 134, + "function": "_active_ddl_guard", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 3.0915000000000005e-05, + "cumulative_seconds": 0.009070625 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1416, + "function": "_read_rowdata_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000352256, + "cumulative_seconds": 0.008963711000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 173, + "function": "_rows", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.3670000000000001e-05, + "cumulative_seconds": 0.008347375 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/__init__.py", + "line": 138, + "function": "jsonify", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.083e-06, + "cumulative_seconds": 0.007388958 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 189, + "function": "response", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.0583000000000003e-05, + "cumulative_seconds": 0.007375958 + }, + { + "file": "python/workspace_api.py", + "line": 61, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.0917000000000006e-05, + "cumulative_seconds": 0.007303917 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1429, + "function": "_read_row_from_packet", + "primitive_calls": 432, + "calls": 432, + "self_seconds": 0.0009377070000000001, + "cumulative_seconds": 0.006798964 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 42, + "function": "", + "primitive_calls": 6012, + "calls": 16026, + "self_seconds": 0.0032064370000000003, + "cumulative_seconds": 0.006170135 + }, + { + "file": "python/workspace_api.py", + "line": 62, + "function": "browser_safe", + "primitive_calls": 1, + "calls": 9641, + "self_seconds": 0.003123751, + "cumulative_seconds": 0.005727708000000001 + }, + { + "file": "python/workspace_api.py", + "line": 66, + "function": "", + "primitive_calls": 1, + "calls": 1363, + "self_seconds": 0.001448367, + "cumulative_seconds": 0.005725916 + }, + { + "file": "python/workspace_api.py", + "line": 68, + "function": "", + "primitive_calls": 2, + "calls": 102, + "self_seconds": 0.000285465, + "cumulative_seconds": 0.005714417 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 205733, + "calls": 205735, + "self_seconds": 0.005465786, + "cumulative_seconds": 0.005466203 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 68, + "function": "", + "primitive_calls": 21, + "calls": 21, + "self_seconds": 0.005024334, + "cumulative_seconds": 0.005024334 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 100027, + "calls": 100027, + "self_seconds": 0.004798761, + "cumulative_seconds": 0.004798761 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 100008, + "calls": 100008, + "self_seconds": 0.004359609, + "cumulative_seconds": 0.004359609 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/converters.py", + "line": 166, + "function": "convert_datetime", + "primitive_calls": 144, + "calls": 144, + "self_seconds": 0.003843023, + "cumulative_seconds": 0.004071424000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 68, + "function": "", + "primitive_calls": 10, + "calls": 10, + "self_seconds": 8.666e-06, + "cumulative_seconds": 0.0035269570000000003 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 44, + "function": "", + "primitive_calls": 2040, + "calls": 2040, + "self_seconds": 0.00043074000000000004, + "cumulative_seconds": 0.0034155410000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 106487, + "calls": 106487, + "self_seconds": 0.003149841, + "cumulative_seconds": 0.003149841 + }, + { + "file": "python/workspace_state_generation.py", + "line": 125, + "function": "_observer_status", + "primitive_calls": 8, + "calls": 8, + "self_seconds": 2.5582e-05, + "cumulative_seconds": 0.002923541 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 38, + "function": "walk", + "primitive_calls": 1, + "calls": 2, + "self_seconds": 0.00109325, + "cumulative_seconds": 0.002918541 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1448, + "function": "_get_descriptions", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000314686, + "cumulative_seconds": 0.0027843380000000004 + }, + { + "file": "python/workspace_state_generation.py", + "line": 115, + "function": "_triggers", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.125e-06, + "cumulative_seconds": 0.002511625 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 163, + "function": "read_length_coded_string", + "primitive_calls": 2720, + "calls": 2720, + "self_seconds": 0.000838437, + "cumulative_seconds": 0.002486345 + }, + { + "file": "python/workspace_state_generation.py", + "line": 107, + "function": "_ddl", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 2.6803e-05, + "cumulative_seconds": 0.0023111670000000003 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 101, + "function": "selected", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.5541000000000002e-05, + "cumulative_seconds": 0.002185667 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 898, + "function": "", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 5.4698000000000004e-05, + "cumulative_seconds": 0.002124293 + }, + { + "file": "python/workspace_curation.py", + "line": 170, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.196e-05, + "cumulative_seconds": 0.002065 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 0.001987042, + "cumulative_seconds": 0.001987042 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 185, + "function": "_metadata", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.5166000000000003e-05, + "cumulative_seconds": 0.0019185410000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 899, + "function": "", + "primitive_calls": 86, + "calls": 86, + "self_seconds": 0.00034863200000000003, + "cumulative_seconds": 0.0018195440000000002 + }, + { + "file": "python/workspace_annotations.py", + "line": 195, + "function": "_chips", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 4.0573e-05, + "cumulative_seconds": 0.0017897870000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 183, + "function": "dumps", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.9003000000000003e-05, + "cumulative_seconds": 0.0017761250000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 183, + "function": "encode", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.3078e-05, + "cumulative_seconds": 0.0017374570000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 205, + "function": "iterencode", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 0.00171046, + "cumulative_seconds": 0.00171046 + }, + { + "file": "python/workspace_annotations.py", + "line": 188, + "function": "_validated_tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.466000000000001e-05, + "cumulative_seconds": 0.0016410840000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 232, + "function": "__init__", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 8.0037e-05, + "cumulative_seconds": 0.001546038 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 166, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.249e-06, + "cumulative_seconds": 0.0015152920000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 236, + "function": "_parse_field_descriptor", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 0.00033823, + "cumulative_seconds": 0.001445171 + }, + { + "file": "python/workspace_explorer.py", + "line": 60, + "function": "protocol_binding_header", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 1.8082e-05, + "cumulative_seconds": 0.001431708 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 282, + "function": "__and__", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 1.0334000000000001e-05, + "cumulative_seconds": 0.001288333 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 178, + "function": "restrict", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 8.7711e-05, + "cumulative_seconds": 0.0012779990000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 223, + "function": "attributes", + "primitive_calls": 1006, + "calls": 1006, + "self_seconds": 0.000372779, + "cumulative_seconds": 0.0011755560000000001 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 24353, + "calls": 24353, + "self_seconds": 0.0010980340000000001, + "cumulative_seconds": 0.0011325320000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 299, + "function": "loads", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 6.333100000000001e-05, + "cumulative_seconds": 0.0010890840000000001 + } + ], + "native_sql_calls": [ + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0007105830009095371 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00037945801159366965 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00019045901717618108 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00038537499494850636 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00021208298858255148 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003357499954290688 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0003048750222660601 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00013566698180511594 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00021674996241927147 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00018758297665044665 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00048754201270639896 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.001238292024936527 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00035670900251716375 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00018274999456480145 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00037170801078900695 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002002500114031136 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00031816697446629405 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00027650000993162394 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00014091696357354522 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0002160840085707605 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.00036791700404137373 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00018166599329560995 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0001682080328464508 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00022583396639674902 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00029612501384690404 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00046079204184934497 + }, + { + "thread": "filter", + "sql_shape": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "seconds": 0.0007599579985253513 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`epoch_uuid`,`included`,`tags`,`review_state`,`revision`,`metadata_fingerprint` FROM `recording_workspace`.`curation` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))AND( ( (`epoch_uuid`='?') OR (", + "seconds": 0.001080457994248718 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`dataset_uuid`,`created_at`,`artifact_sha256` FROM `recording_workspace`.`dataset_revision` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00025554205058142543 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.005455167032778263 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.0006175000453367829 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0003607079852372408 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0002090420457534492 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00024645798839628696 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0003185420064255595 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.000686249986756593 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.000373166985809803 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00021479197312146425 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004089579451829195 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00023245898773893714 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003435830003581941 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00036641600308939815 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.0001425419468432665 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00022420799359679222 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.0001866249949671328 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005071249906904995 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.001263874990399927 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003494580159895122 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.0002049999893642962 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00038958300137892365 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00023395800963044167 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00034787500044330955 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00028849998489022255 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00015437498223036528 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00026966602308675647 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004118329961784184 + } + ], + "limits": "Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap." + }, + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": "const,const", + "rows": 20, + "filtered": 10.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.054597 + } + }, + "project_uuid": "4dff9ec3-f69a-4387-9e77-a43eb4b14f4a", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.139045 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.052419 + } + }, + "project_uuid": "4dff9ec3-f69a-4387-9e77-a43eb4b14f4a", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.181751 + }, + "seconds": 0.32084808399667963, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "workflow_peak_rss_before_durable_oracle_bytes": 988856320, + "durable_snapshot_verify_seconds": 7.740958750015125, + "loaded_product_modules": { + "workspace_tree": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tree.py", + "workspace_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_predicates.py", + "workspace_cache_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_cache_lifecycle.py", + "workspace_metadata_objects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_metadata_objects.py", + "workspace_disk_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_disk_index.py", + "workspace_catalog_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_catalog_identity.py", + "recording_workspace": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/recording_workspace.py", + "workspace_recipes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_recipes.py", + "workspace_tree_code": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tree_code.py", + "workspace_service": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_service.py", + "workspace_tree_pages": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tree_pages.py", + "workspace_projects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_projects.py", + "workspace_mysql_profile": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_mysql_profile.py", + "workspace_native_mysql": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_native_mysql.py", + "workspace_mysql_runtime": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_mysql_runtime.py", + "workspace_storage": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_storage.py", + "workspace_diff": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_diff.py", + "workspace_protocol_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_protocol_identity.py", + "workspace_import_check": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_import_check.py", + "workspace_audit": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_audit.py", + "workspace_api": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_api.py", + "workspace_state_snapshot": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_state_snapshot.py", + "workspace_author_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_author_preferences.py", + "workspace_curation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_curation.py", + "workspace_annotations": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_annotations.py", + "workspace_shared_tag_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_shared_tag_index.py", + "workspace_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_paths.py", + "workspace_desktop_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_desktop_paths.py", + "workspace_startup_registry": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_startup_registry.py", + "workspace_explorer": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_explorer.py", + "workspace_datastores": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_datastores.py", + "workspace_suggestions": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_suggestions.py", + "workspace_tag_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tag_predicates.py", + "workspace_export_folder": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_export_folder.py", + "workspace_import_progress": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_import_progress.py", + "workspace_project_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_project_preferences.py", + "workspace_protocol_state": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_protocol_state.py", + "workspace_state_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_state_generation.py", + "workspace_project_servers": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_project_servers.py", + "workspace_launcher": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_launcher.py", + "workspace_app_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_app_routes.py", + "workspace_folder_browser": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_folder_browser.py", + "workspace_h5_inbox": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_h5_inbox.py", + "workspace_tag_exchange": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tag_exchange.py", + "workspace_external_tags": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_external_tags.py", + "workspace_qc": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_qc.py", + "workspace_search": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_search.py", + "workspace_matlab_masks": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_matlab_masks.py", + "workspace_matlab_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_matlab_routes.py", + "workspace_mask_refresh": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_mask_refresh.py", + "workspace_matching_epochs": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_matching_epochs.py", + "workspace_candidate_exports": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_candidate_exports.py", + "workspace_backup_scheduler": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_backup_scheduler.py", + "workspace_recovery_store": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_recovery_store.py", + "workspace_recovery_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_recovery_generation.py", + "workspace_annotation_preparation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_annotation_preparation.py", + "workspace_native_tag_lookup": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_native_tag_lookup.py", + "workspace_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_lifecycle.py", + "workspace_native_tag_filter": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_native_tag_filter.py" + }, + "owned_native_runtime_stopped": true, + "source_inventory_after": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "d81d9c5e03e62024c30474612596ee3fec2753a745e39c2db005010c85b8ffff", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "b70fe1d82baa6ab40901d17e49ef8946297379a6d1adc3929a9cb979ae947e5a", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_empty_blocks.py": "ff0973074a72cf110b90dd8f76f032d5016315bbb21f84569e9fa701b11a7d88", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3cf4ab9a1b5db849600c2716e9026cfb3d0817389f240d5d9cee9dbfe0b7922d", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "a7bc5ddb5f153aacb23c13eb11b1ca14515ddcd12526567f41e49252931ddf96", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "9bf32c59a9847f5b7231987348fd54ad1f6eec4773323b125ae34d1239632fbb", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "8cb336a98cf2f487a3bf30db1ddc6ad5db1081018cee394d2690dffa04f8c1bd", + "python/workspace_native_tag_lookup.py": "ae8d7fd3b2f80d56078777b03de4189b648f536ead1ca1225ad6c72a7c59a466", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "68e142d6008248c67310462b692b130f0951a87a802187f59d0e6302a78073fc", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "source_unchanged": true, + "harness_unchanged": true, + "seconds": 219.8653925419785, + "finished_at": "2026-09-30T15:43:14.953838+00:00", + "peak_rss_bytes": 988856320, + "passed": true +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-500.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-500.json new file mode 100644 index 0000000..34c6ecd --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-500.json @@ -0,0 +1,3743 @@ +{ + "scope": "Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy.\n\nEvery project/database is disposable. Acquisition metadata is synthetic; actual\nMySQL, triggers, Flask routes, derived indexes and each version's save hooks\nare used. Native SQL commits are checked immediately; any background recovery\nmirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude\noracle work, and do not model browser concurrency/rendering. Sequential bundle\ntimes are sums of their separately measured requests. Profiles are separate.\n", + "epochs": 500, + "profiles": 3, + "tags_per_annotation": 5, + "protocols": 2, + "samples": 5, + "source_root": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq", + "source_inventory_before": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "d81d9c5e03e62024c30474612596ee3fec2753a745e39c2db005010c85b8ffff", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "b70fe1d82baa6ab40901d17e49ef8946297379a6d1adc3929a9cb979ae947e5a", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_empty_blocks.py": "ff0973074a72cf110b90dd8f76f032d5016315bbb21f84569e9fa701b11a7d88", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3cf4ab9a1b5db849600c2716e9026cfb3d0817389f240d5d9cee9dbfe0b7922d", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "a7bc5ddb5f153aacb23c13eb11b1ca14515ddcd12526567f41e49252931ddf96", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "9bf32c59a9847f5b7231987348fd54ad1f6eec4773323b125ae34d1239632fbb", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "8cb336a98cf2f487a3bf30db1ddc6ad5db1081018cee394d2690dffa04f8c1bd", + "python/workspace_native_tag_lookup.py": "ae8d7fd3b2f80d56078777b03de4189b648f536ead1ca1225ad6c72a7c59a466", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "68e142d6008248c67310462b692b130f0951a87a802187f59d0e6302a78073fc", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "fixture_module": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py", + "harness_sha256": "26d058c7a3b9c5f67071e38d70df66a566b37cef7b543656b0bcb521c04df133", + "started_at": "2026-09-30T15:38:53.807470+00:00", + "release_ready": false, + "operations": { + "first10_revision_preflight": { + "samples_seconds": [ + 0.012720917002297938, + 0.006726875028107315, + 0.006913584016729146, + 0.006534375017508864, + 0.006501541996840388 + ], + "p50_seconds": 0.006726875028107315, + "p95_seconds": 0.012720917002297938, + "p99_seconds": 0.012720917002297938, + "maximum_seconds": 0.012720917002297938, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 21988, + "Questions": 11 + }, + { + "Bytes_sent": 15362, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + } + ] + }, + "first10_save": { + "samples_seconds": [ + 0.04435537499375641, + 0.020486874971538782, + 0.01931745803449303, + 0.020893458975479007, + 0.018624041986186057 + ], + "p50_seconds": 0.020486874971538782, + "p95_seconds": 0.04435537499375641, + "p99_seconds": 0.04435537499375641, + "maximum_seconds": 0.04435537499375641, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 24816, + "Questions": 43 + }, + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12423, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + } + ] + }, + "second10_revision_preflight": { + "samples_seconds": [ + 0.006306124967522919, + 0.005953916988801211, + 0.005990375007968396, + 0.006277291977312416, + 0.005971791979391128 + ], + "p50_seconds": 0.005990375007968396, + "p95_seconds": 0.006306124967522919, + "p99_seconds": 0.006306124967522919, + "maximum_seconds": 0.006306124967522919, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15380, + "Questions": 4 + }, + { + "Bytes_sent": 15380, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + } + ] + }, + "second10_save": { + "samples_seconds": [ + 0.020426875038538128, + 0.019969207991380244, + 0.019461542018689215, + 0.022125250019598752, + 0.017878333979751915 + ], + "p50_seconds": 0.019969207991380244, + "p95_seconds": 0.022125250019598752, + "p99_seconds": 0.022125250019598752, + "maximum_seconds": 0.022125250019598752, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12435, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + } + ] + }, + "filter20": { + "samples_seconds": [ + 0.03314845898421481, + 0.02440887497505173, + 0.024143457994796336, + 0.02458608301822096, + 0.024433874990791082 + ], + "p50_seconds": 0.024433874990791082, + "p95_seconds": 0.03314845898421481, + "p99_seconds": 0.03314845898421481, + "maximum_seconds": 0.03314845898421481, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 164693, + "Questions": 71 + }, + { + "Bytes_sent": 151637, + "Questions": 57 + }, + { + "Bytes_sent": 151638, + "Questions": 57 + }, + { + "Bytes_sent": 151638, + "Questions": 57 + }, + { + "Bytes_sent": 151638, + "Questions": 57 + } + ] + }, + "cell_save": { + "samples_seconds": [ + 0.01293837500270456, + 0.007577875046990812, + 0.008321208006236702, + 0.007441041991114616, + 0.011222417000681162 + ], + "p50_seconds": 0.008321208006236702, + "p95_seconds": 0.01293837500270456, + "p99_seconds": 0.01293837500270456, + "maximum_seconds": 0.01293837500270456, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4165, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + } + ] + }, + "filter_cell100": { + "samples_seconds": [ + 0.043737958010751754, + 0.040947375004179776, + 0.04169049998745322, + 0.04436779202660546, + 0.061345916998106986 + ], + "p50_seconds": 0.043737958010751754, + "p95_seconds": 0.061345916998106986, + "p99_seconds": 0.061345916998106986, + "maximum_seconds": 0.061345916998106986, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 184944, + "Questions": 57 + }, + { + "Bytes_sent": 184946, + "Questions": 57 + }, + { + "Bytes_sent": 184947, + "Questions": 57 + }, + { + "Bytes_sent": 184947, + "Questions": 57 + }, + { + "Bytes_sent": 184947, + "Questions": 57 + } + ] + }, + "filter_cell_and_epoch10": { + "samples_seconds": [ + 0.01991629198892042, + 0.02576245804084465, + 0.019896209007129073, + 0.027239874994847924, + 0.02231991698499769 + ], + "p50_seconds": 0.02231991698499769, + "p95_seconds": 0.027239874994847924, + "p99_seconds": 0.027239874994847924, + "maximum_seconds": 0.027239874994847924, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 142260, + "Questions": 58 + }, + { + "Bytes_sent": 142262, + "Questions": 58 + }, + { + "Bytes_sent": 142263, + "Questions": 58 + }, + { + "Bytes_sent": 142263, + "Questions": 58 + }, + { + "Bytes_sent": 142263, + "Questions": 58 + } + ] + }, + "remove_first10_revision_preflight": { + "samples_seconds": [ + 0.00645416701445356, + 0.007006958010606468, + 0.0065083749941550195, + 0.008010582998394966, + 0.007031750050373375 + ], + "p50_seconds": 0.007006958010606468, + "p95_seconds": 0.008010582998394966, + "p99_seconds": 0.008010582998394966, + "maximum_seconds": 0.008010582998394966, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15799, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + } + ] + }, + "remove_first10_save": { + "samples_seconds": [ + 0.02056591701693833, + 0.020229208981618285, + 0.020022916025482118, + 0.023306625022087246, + 0.019760082999709994 + ], + "p50_seconds": 0.020229208981618285, + "p95_seconds": 0.023306625022087246, + "p99_seconds": 0.023306625022087246, + "maximum_seconds": 0.023306625022087246, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12423, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + } + ] + }, + "filter_hierarchy_after_epoch_remove": { + "samples_seconds": [ + 0.01473995903506875, + 0.01622966700233519, + 0.013781792018562555, + 0.01838954200502485, + 0.013457374996505678 + ], + "p50_seconds": 0.01473995903506875, + "p95_seconds": 0.01838954200502485, + "p99_seconds": 0.01838954200502485, + "maximum_seconds": 0.01838954200502485, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 129792, + "Questions": 55 + }, + { + "Bytes_sent": 129795, + "Questions": 55 + }, + { + "Bytes_sent": 129795, + "Questions": 55 + }, + { + "Bytes_sent": 129795, + "Questions": 55 + }, + { + "Bytes_sent": 129795, + "Questions": 55 + } + ] + }, + "filter_remaining10": { + "samples_seconds": [ + 0.020654416002798826, + 0.018453792028594762, + 0.03207512496737763, + 0.020965208997949958, + 0.02284891699673608 + ], + "p50_seconds": 0.020965208997949958, + "p95_seconds": 0.03207512496737763, + "p99_seconds": 0.03207512496737763, + "maximum_seconds": 0.03207512496737763, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 141495, + "Questions": 57 + }, + { + "Bytes_sent": 141498, + "Questions": 57 + }, + { + "Bytes_sent": 141498, + "Questions": 57 + }, + { + "Bytes_sent": 141498, + "Questions": 57 + }, + { + "Bytes_sent": 141498, + "Questions": 57 + } + ] + }, + "remove_second10_revision_preflight": { + "samples_seconds": [ + 0.006793082982767373, + 0.00652279204223305, + 0.006486875005066395, + 0.006847209006082267, + 0.006438792042899877 + ], + "p50_seconds": 0.00652279204223305, + "p95_seconds": 0.006847209006082267, + "p99_seconds": 0.006847209006082267, + "maximum_seconds": 0.006847209006082267, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + } + ] + }, + "remove_second10_save": { + "samples_seconds": [ + 0.021633083990309387, + 0.024006791994906962, + 0.024302124977111816, + 0.026654709014110267, + 0.020078167028259486 + ], + "p50_seconds": 0.024006791994906962, + "p95_seconds": 0.026654709014110267, + "p99_seconds": 0.026654709014110267, + "maximum_seconds": 0.026654709014110267, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12435, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + } + ] + }, + "filter_after_all_epoch_removals": { + "samples_seconds": [ + 0.015067917003761977, + 0.015604250016622245, + 0.015238874999340624, + 0.013582250045146793, + 0.013563792046625167 + ], + "p50_seconds": 0.015067917003761977, + "p95_seconds": 0.015604250016622245, + "p99_seconds": 0.015604250016622245, + "maximum_seconds": 0.015604250016622245, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 129035, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + } + ] + }, + "remove_cell_save": { + "samples_seconds": [ + 0.007775167003273964, + 0.008647124981507659, + 0.009320041979663074, + 0.007871415989939123, + 0.008884500013664365 + ], + "p50_seconds": 0.008647124981507659, + "p95_seconds": 0.009320041979663074, + "p99_seconds": 0.009320041979663074, + "maximum_seconds": 0.009320041979663074, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4165, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + } + ] + }, + "filter_after_cell_removal": { + "samples_seconds": [ + 0.014741291000973433, + 0.01508387498324737, + 0.014086208015214652, + 0.013328332977835089, + 0.015477415989153087 + ], + "p50_seconds": 0.014741291000973433, + "p95_seconds": 0.015477415989153087, + "p99_seconds": 0.015477415989153087, + "maximum_seconds": 0.015477415989153087, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 129035, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + }, + { + "Bytes_sent": 129038, + "Questions": 54 + } + ] + }, + "tag10_then10_filter20_http_total": { + "samples_seconds": [ + 0.11695775098633021, + 0.07754574995487928, + 0.07582641707267612, + 0.08041645900812, + 0.07340958493296057 + ], + "p50_seconds": 0.07754574995487928, + "p95_seconds": 0.11695775098633021, + "p99_seconds": 0.11695775098633021, + "maximum_seconds": 0.11695775098633021, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "cell_tag_then_cell_filter_http_total": { + "samples_seconds": [ + 0.056676333013456315, + 0.04852525005117059, + 0.050011707993689924, + 0.05180883401772007, + 0.07256833399878815 + ], + "p50_seconds": 0.05180883401772007, + "p95_seconds": 0.07256833399878815, + "p99_seconds": 0.07256833399878815, + "maximum_seconds": 0.07256833399878815, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "first10_selected_action_http_total": { + "samples_seconds": [ + 0.05707629199605435, + 0.027213749999646097, + 0.026231042051222175, + 0.02742783399298787, + 0.025125583983026445 + ], + "p50_seconds": 0.027213749999646097, + "p95_seconds": 0.05707629199605435, + "p99_seconds": 0.05707629199605435, + "maximum_seconds": 0.05707629199605435, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "second10_selected_action_http_total": { + "samples_seconds": [ + 0.026733000006061047, + 0.025923124980181456, + 0.02545191702665761, + 0.028402541996911168, + 0.023850125959143043 + ], + "p50_seconds": 0.025923124980181456, + "p95_seconds": 0.028402541996911168, + "p99_seconds": 0.028402541996911168, + "maximum_seconds": 0.028402541996911168, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "autocomplete_cold_diagnostic": { + "samples_seconds": [ + 0.02161020803032443 + ], + "p50_seconds": 0.02161020803032443, + "p95_seconds": 0.02161020803032443, + "p99_seconds": 0.02161020803032443, + "maximum_seconds": 0.02161020803032443, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 249865, + "Questions": 95 + } + ] + }, + "autocomplete_warm_diagnostic": { + "samples_seconds": [ + 0.02496337500633672 + ], + "p50_seconds": 0.02496337500633672, + "p95_seconds": 0.02496337500633672, + "p99_seconds": 0.02496337500633672, + "maximum_seconds": 0.02496337500633672, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 249865, + "Questions": 95 + } + ] + }, + "autocomplete_empty_diagnostic": { + "samples_seconds": [ + 0.030342624988406897 + ], + "p50_seconds": 0.030342624988406897, + "p95_seconds": 0.030342624988406897, + "p99_seconds": 0.030342624988406897, + "maximum_seconds": 0.030342624988406897, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 257580, + "Questions": 116 + } + ] + }, + "same_server_native_reuse_filter20": { + "samples_seconds": [ + 0.026880667021032423 + ], + "p50_seconds": 0.026880667021032423, + "p95_seconds": 0.026880667021032423, + "p99_seconds": 0.026880667021032423, + "maximum_seconds": 0.026880667021032423, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 151639, + "Questions": 57 + } + ] + } + }, + "checks": [ + { + "name": "populated_native_migration_ready_before_timed_operations", + "passed": true + }, + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "autocomplete_has_no_membership_aggregation", + "passed": true, + "membership_selects": 30, + "maximum_rows_per_seek": 1 + }, + { + "name": "autocomplete_compact_dictionary_fetches_are_bounded", + "passed": true, + "dictionary_selects": 9, + "scope": "Counts may scan matching compact entries; no unbounded dictionary rows are fetched for Python prefix filtering." + }, + { + "name": "autocomplete_membership_winner_seeks_are_indexed", + "passed": true, + "plans": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 167 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "page_cells": true, + "target_specification": "tag10_then10_filter20_and_cell_epoch_hierarchy", + "baseline_harness_sha256": "272fe050c8762ed4ea45bd013e236e8723d8fe46f5e7e293c58e2edf1fd52ddc", + "mysql_version": "8.4.2", + "seed_seconds": 0.08865733398124576, + "populated_native_startup_seconds": 1.002701541990973, + "fixture_construction": { + "strategy": "canonical seed before normal app startup and populated native migration", + "native_derived_tables_absent_during_seed": true, + "canonical_shared_records": 1515, + "canonical_curation_records": 1000, + "product_triggers_disabled_during_timed_operations": false + }, + "seed_checkpoint_seconds": 0.05130733299301937, + "native_lookup_startup_preparation": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.06283 + } + }, + "project_uuid": "69b6a7e7-762d-4adf-ad65-b1c3a8eff7f1", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.436276 + }, + "selected_epoch_uuids": { + "first10": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5" + ], + "second10": [ + "ad573668-6512-6e55-649e-cb23ae1d4888", + "16dc368a-89b4-28b2-4854-84313ba67a39", + "37834f2f-2576-2f23-e1f7-4a531cbe445d", + "454f63ac-30c8-3229-97ef-025edff6abd2", + "5ef6fdf3-2513-aa7c-d11f-72beccf132b9", + "1253e937-3e78-1b75-0026-6caa55150e08", + "482d9673-cfee-5de3-91f9-7fde4d1c84f9", + "3346f2bb-f6c3-4bd2-dbe2-8bd1bb657d0e", + "9537f32e-c759-9e1a-e953-af6c9f929fe7", + "0fd42b3f-73c4-48b3-4940-b339f87d07ad" + ], + "cell": "0604cd31-38fe-ed20-2ef2-93e062da2f47", + "cell_children": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5", + "4a44dc15-3642-04a8-0fe8-0e9039455cc1", + "4fc82b26-aecb-47d2-868c-4efbe3581732", + "6b51d431-df5d-7f14-1cbe-ceccf79edf3d", + "3fdba35f-04dc-8c46-2986-c992bcf87554", + "8527a891-e224-1369-50ff-32ca212b45bc", + "e629fa65-98d7-3276-8f7c-726b4b621285", + "b17ef6d1-9c7a-5b1e-e83b-907c595526dc", + "4523540f-1504-cd17-100c-4835e85b7eef", + "4ec9599f-c203-d176-a301-536c2e091a19", + "9400f1b2-1cb5-27d7-fa3d-3eabba93557a", + "f5ca38f7-48a1-d6ea-f726-b8a42fb575c3", + "6f4b6612-125f-b3a0-daec-d2799dfd6c9c", + "785f3ec7-eb32-f30b-90cd-0fcf3657d388", + "535fa30d-7e25-dd8a-49f1-536779734ec8", + "c2356069-e9d1-e79c-a924-378153cfbbfb", + "b7a56873-cd77-1f2c-446d-369b649430b6", + "5f9c4ab0-8cac-7457-e911-1a30e4664920", + "670671cd-9740-4156-226e-507973f2ab83", + "59e19706-d51d-39f6-6711-c2653cd7eb12", + "35135aaa-6cc2-3891-b40c-b3f378c53a17", + "624b60c5-8c9d-8bfb-6ff1-886c2fd605d2", + "eb1e33e8-a81b-697b-7585-5af6bfcdbcbf", + "e29c9c18-0c62-79b0-b02a-bd6a1801c7c0", + "c6f3ac57-944a-5314-90cd-39902d0f7777", + "86e50149-6586-6131-2a9e-0b35558d84f6", + "9f14025a-f006-5b30-e47e-23ebb3b491d3", + "76a50887-d8f1-c2e9-3017-55428990ad81", + "7a61b537-01be-fdae-0eee-ffaecc73f14e", + "aea92132-c4cb-eb26-3e6a-c2bf6c183b5d", + "0b918943-df09-62bc-7a18-24c0555a3893", + "d59eced1-ded0-7f84-c145-592f65bdf854", + "3d914f93-48c9-cc0f-f8a7-9716700b9fcd", + "73475cb4-0a56-8e8d-a8a0-45ced110137e", + "44cb730c-4204-80a0-477b-505ae68af508", + "71ee45a3-c0db-9a98-65f7-313dd3372cf6", + "811786ad-1ae7-4adf-dd20-dd0372abaaeb", + "25fc0e70-96fc-6537-1820-2dc30b0c580b", + "31489056-e091-6d59-fe3a-dd79e63f095a", + "98010bd9-270f-9b10-0b62-14a21754fd33", + "0e17daca-5f3e-175f-448b-acace3bc0da4", + "1a656259-0ef1-9d10-45d0-6c4055742d38", + "031b4af5-197e-c30a-926f-48cf40e11a7d", + "41cfc0d1-f2d1-27b0-4555-b7246d84019b", + "2858dcd1-057d-3eae-7f7d-5f782167e24b", + "2fca346d-b656-1871-02ce-806ac732e06a", + "02d20bbd-7e39-4ad5-999a-4cebabac9619", + "7688b6ef-5255-5962-d008-fff894223582", + "c837649c-ce43-f272-9138-e72cc3152070", + "6208ef0f-7750-c111-548c-f90b6ea1d0d0", + "3e1e967e-9b79-3e90-8f8e-ae83c74dba9b", + "39fa9ec1-90ee-e7b6-f4df-f1100d6343e1", + "d029fa3a-95e1-74a1-9934-857f535eb942", + "81b8a03f-97e8-787c-53fe-1a86bda042b6", + "da4ea2a5-506f-2693-eae1-90d9360a1f31", + "a68b412c-4282-555f-1554-6cf6e1fc4289", + "108c995b-953c-8a35-5611-03e2014cf828", + "3ada92f2-8b4c-eda3-8562-ebf047c6ff05", + "49d180ec-f561-3281-9571-bf39d9b7b342", + "a21855da-08cb-102d-1d21-7c53dc5824a3", + "c75cb66a-e28d-8ebc-6ede-d002c28a8ba0", + "ff5a1ae0-12af-a5d4-c889-c50ad427aaf5", + "7f2253d7-e228-b22a-08bd-a1f09c516f6f", + "87226162-0421-7edd-b39e-7df969e0698a", + "96061e92-f58e-4bdc-dee7-3df36183fe3a", + "eb624dbe-56eb-6620-ae62-080c10a273ca", + "f369cb89-fc62-7e66-8987-007d121ed1ea", + "f74efabe-f12e-a619-e30b-79bddef89cff", + "a88a7902-cb4e-f697-ba0b-6759c50e8c10", + "349c4120-1b62-db85-1192-665c504b350f", + "98a3ab7c-340e-8a03-3e7b-37b6ef942875", + "48449a14-a4ff-7d79-bb7a-1b6f3d488eba", + "5316ca1c-5ddc-a8e6-cecc-fce58f3b8540", + "a46e3763-2fa6-ca51-a13f-e39a567b3c23", + "bbb965ab-0c80-d653-8cf2-184babad2a56", + "44c8031c-b036-a735-0d8b-9b8603af662a", + "b4944c6f-f08d-c6f4-3da2-e9c824669b7d", + "434c9b5a-e514-646b-bd91-b50032ca579e", + "bdd2d3af-3a5a-1213-497d-4f1f7bfcda89", + "8b940be7-fb78-aaa6-b656-7dd7a3987996", + "cd70bea0-23f7-52a0-564a-bb6ed08d42c1", + "69f59c27-3b6e-669a-c32a-6dd5e1b2cb63", + "1da51b8d-8ff9-8f6a-48f8-0ae79fe3ca6c", + "82416496-09f8-8ccd-2a0a-5b233a07a538", + "6e400187-1c0c-f27c-7634-ef1dc478408f", + "e3d6c4d4-599e-0088-2384-ca981ee287ed", + "ad48ff99-415b-2f00-7dc3-5b7eb553fd1e", + "7b1a278f-5abe-8e9d-a907-fc9c29dfd432", + "d6d824ab-ba4a-fde8-1129-c71dea75b810", + "29db0c67-82db-d500-0559-ef4d9e953e30", + "8c1f1046-219d-dd21-6a02-3f792356ddf1" + ] + }, + "backup_receipts": [ + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 1, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 2, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 3, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 4, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 5, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 6, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 7, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 8, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 9, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 10, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 11, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 12, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 13, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 14, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 15, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 16, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 17, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 18, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 19, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 20, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 21, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 22, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 23, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 24, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 25, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 26, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 27, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 28, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 29, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 30, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_first10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:39:03.414050+00:00", + "pending": true, + "requested_sequence": 31, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_second10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:39:03.414050+00:00", + "pending": true, + "requested_sequence": 32, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_first10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:39:03.771515+00:00", + "pending": true, + "requested_sequence": 33, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_second10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:39:03.771515+00:00", + "pending": true, + "requested_sequence": 34, + "running": false, + "status": "pending" + }, + "database": "committed" + } + } + ], + "preparation_index_seconds": 0, + "lookup_mode": "persistent_native_sql_no_post_seed_tag_cache_preparation", + "bundle_definitions": { + "tag10_then10_filter20_http_total": [ + "first10_revision_preflight", + "first10_save", + "second10_revision_preflight", + "second10_save", + "filter20" + ], + "cell_tag_then_cell_filter_http_total": [ + "cell_save", + "filter_cell100" + ], + "first10_selected_action_http_total": [ + "first10_revision_preflight", + "first10_save" + ], + "second10_selected_action_http_total": [ + "second10_revision_preflight", + "second10_save" + ] + }, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:39:04.669427+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.00012283300748094916, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.0001301250304095447, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00014424999244511127, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.00013224995927885175, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001396249863319099, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013120798394083977, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011324998922646046, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00016866601072251797, + "result_rows": 3 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0001443749642930925, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.000144040968734771, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.0001740000443533063, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.00016950001008808613, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00016325002070516348, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013179198140278459, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00019791699014604092, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00021045899484306574, + "result_rows": 3 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0002182909520342946, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "seconds": 0.00022295804228633642, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.0002453330089338124, + "result_rows": 12 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0002537500113248825, + "result_rows": 24 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014916702639311552, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013404199853539467, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011974998051300645, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00017691700486466289, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013070798013359308, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011962500866502523, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012362503912299871, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012741703540086746, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001378749730065465, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013474997831508517, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001284580212086439, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001437499886378646, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013579102233052254, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013800000306218863, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011987495236098766, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011399999493733048, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011145800817757845, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011766701936721802, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011616700794547796, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012120796600356698, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00020866701379418373, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00018604198703542352, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010916695464402437, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010958401253446937, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0004837500164285302, + "result_rows": 9 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": "const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using index condition; Using filesort" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "38", + "ref": "const", + "rows": 41, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_rank", + "key": "by_rank", + "key_len": "38", + "ref": "const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 24, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 9, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "filter20_cpu_profile": { + "top_functions": [ + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 367, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.1124e-05, + "cumulative_seconds": 0.061389000000000006 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 178, + "function": "request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.125e-06, + "cumulative_seconds": 0.061336792 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1163, + "function": "get", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.792000000000001e-06, + "cumulative_seconds": 0.06049525 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/testing.py", + "line": 204, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.2833e-05, + "cumulative_seconds": 0.060489458 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1062, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.207e-06, + "cumulative_seconds": 0.060191083000000006 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 984, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0500000000000001e-05, + "cumulative_seconds": 0.06017675 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1230, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.792e-06, + "cumulative_seconds": 0.059981458 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1529, + "function": "__call__", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.2080000000000005e-06, + "cumulative_seconds": 0.059950750000000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1479, + "function": "wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.0751000000000002e-05, + "cumulative_seconds": 0.059944542 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 904, + "function": "full_dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.168000000000001e-06, + "cumulative_seconds": 0.059649958 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 879, + "function": "dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000106582, + "cumulative_seconds": 0.059401958000000005 + }, + { + "file": "python/workspace_api.py", + "line": 716, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.7089e-05, + "cumulative_seconds": 0.059291750000000004 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 358, + "function": "traced_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00026604600000000003, + "cumulative_seconds": 0.024827042 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 412, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00012503200000000002, + "cumulative_seconds": 0.024108872 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 27, + "calls": 38, + "self_seconds": 3.158e-05, + "cumulative_seconds": 0.024036416 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 249, + "function": "native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.2417000000000002e-05, + "cumulative_seconds": 0.0239665 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 402, + "function": "_execute_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000135208, + "cumulative_seconds": 0.023781291000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 150, + "function": "execute", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.367e-05, + "cumulative_seconds": 0.023339248 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 332, + "function": "_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 8.504e-05, + "cumulative_seconds": 0.022810372000000002 + }, + { + "file": "python/workspace_annotations.py", + "line": 295, + "function": "for_epochs", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000122533, + "cumulative_seconds": 0.022550583000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 575, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 8.654100000000001e-05, + "cumulative_seconds": 0.022253747 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 851, + "function": "_read_query_result", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.2786e-05, + "cumulative_seconds": 0.021033123 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1288, + "function": "read", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 8.592800000000001e-05, + "cumulative_seconds": 0.020935212 + }, + { + "file": "python/workspace_state_generation.py", + "line": 101, + "function": "_rows", + "primitive_calls": 46, + "calls": 46, + "self_seconds": 6.7877e-05, + "cumulative_seconds": 0.019479081000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 197, + "function": "response_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.0918000000000004e-05, + "cumulative_seconds": 0.019120916 + }, + { + "file": "python/workspace_state_generation.py", + "line": 233, + "function": "_attest_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 7.7917e-05, + "cumulative_seconds": 0.019074625 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 128, + "function": "deepcopy", + "primitive_calls": 78, + "calls": 17170, + "self_seconds": 0.009763469, + "cumulative_seconds": 0.016600959000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 201, + "function": "_deepcopy_list", + "primitive_calls": 62, + "calls": 102, + "self_seconds": 0.000320709, + "cumulative_seconds": 0.016466456 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 763, + "function": "_read_packet", + "primitive_calls": 769, + "calls": 769, + "self_seconds": 0.0012844870000000002, + "cumulative_seconds": 0.015917263 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 227, + "function": "_deepcopy_dict", + "primitive_calls": 1242, + "calls": 1284, + "self_seconds": 0.002916516, + "cumulative_seconds": 0.014378134 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 813, + "function": "_read_bytes", + "primitive_calls": 1538, + "calls": 1538, + "self_seconds": 0.0005917450000000001, + "cumulative_seconds": 0.012605694 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 141, + "function": "__exit__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 4.542e-06, + "cumulative_seconds": 0.012342083 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 1538, + "calls": 1538, + "self_seconds": 0.000241913, + "cumulative_seconds": 0.011928618 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/socket.py", + "line": 704, + "function": "readinto", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 9.7377e-05, + "cumulative_seconds": 0.011686705 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 132, + "function": "__enter__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 3.0020000000000002e-06, + "cumulative_seconds": 0.011631209 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1299, + "function": "recv_into", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 9.885900000000001e-05, + "cumulative_seconds": 0.011547792000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1157, + "function": "read", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 5.5245000000000004e-05, + "cumulative_seconds": 0.011437707 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 69, + "calls": 69, + "self_seconds": 0.011377330000000001, + "cumulative_seconds": 0.011377330000000001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 134, + "function": "_active_ddl_guard", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 4.6920000000000005e-05, + "cumulative_seconds": 0.01135325 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1370, + "function": "_read_result_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.7586e-05, + "cumulative_seconds": 0.008834206 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 869, + "function": "to_dicts", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.5211000000000003e-05, + "cumulative_seconds": 0.007760958 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/__init__.py", + "line": 138, + "function": "jsonify", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.208e-06, + "cumulative_seconds": 0.007474459 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 189, + "function": "response", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.9584e-05, + "cumulative_seconds": 0.0074592090000000005 + }, + { + "file": "python/workspace_api.py", + "line": 61, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.8416000000000005e-05, + "cumulative_seconds": 0.007350541 + }, + { + "file": "python/workspace_api.py", + "line": 62, + "function": "browser_safe", + "primitive_calls": 1, + "calls": 9641, + "self_seconds": 0.003248995, + "cumulative_seconds": 0.005733625 + }, + { + "file": "python/workspace_api.py", + "line": 66, + "function": "", + "primitive_calls": 1, + "calls": 1363, + "self_seconds": 0.001419317, + "cumulative_seconds": 0.0057311670000000006 + }, + { + "file": "python/workspace_api.py", + "line": 68, + "function": "", + "primitive_calls": 2, + "calls": 102, + "self_seconds": 0.000207082, + "cumulative_seconds": 0.005717626 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1416, + "function": "_read_rowdata_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000383267, + "cumulative_seconds": 0.005678291 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 1231, + "function": "cursor", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 1.775e-05, + "cumulative_seconds": 0.00552504 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 268, + "function": "_native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.85e-05, + "cumulative_seconds": 0.004784626 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 311, + "function": "native_context", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.2168e-05, + "cumulative_seconds": 0.004706667 + }, + { + "file": "python/workspace_annotations.py", + "line": 173, + "function": "_rows", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.4541e-05, + "cumulative_seconds": 0.004698583 + }, + { + "file": "python/workspace_state_generation.py", + "line": 125, + "function": "_observer_status", + "primitive_calls": 8, + "calls": 8, + "self_seconds": 3.8249e-05, + "cumulative_seconds": 0.0037859160000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1429, + "function": "_read_row_from_packet", + "primitive_calls": 432, + "calls": 432, + "self_seconds": 0.0009958130000000001, + "cumulative_seconds": 0.0034007150000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1448, + "function": "_get_descriptions", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000369963, + "cumulative_seconds": 0.003054204 + }, + { + "file": "python/workspace_state_generation.py", + "line": 115, + "function": "_triggers", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.416e-06, + "cumulative_seconds": 0.002936333 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 163, + "function": "read_length_coded_string", + "primitive_calls": 2720, + "calls": 2720, + "self_seconds": 0.0008828200000000001, + "cumulative_seconds": 0.002681516 + }, + { + "file": "python/workspace_state_generation.py", + "line": 107, + "function": "_ddl", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 6.2131e-05, + "cumulative_seconds": 0.002629792 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 898, + "function": "", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 5.5992e-05, + "cumulative_seconds": 0.0022069570000000003 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 185, + "function": "_metadata", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.0167e-05, + "cumulative_seconds": 0.0021745830000000003 + }, + { + "file": "python/workspace_annotations.py", + "line": 195, + "function": "_chips", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 4.074e-05, + "cumulative_seconds": 0.0020089540000000003 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 183, + "function": "dumps", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 3.0506000000000002e-05, + "cumulative_seconds": 0.0018869190000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 899, + "function": "", + "primitive_calls": 86, + "calls": 86, + "self_seconds": 0.00036520000000000004, + "cumulative_seconds": 0.0018852920000000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 101, + "function": "selected", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.0709e-05, + "cumulative_seconds": 0.0018731660000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 188, + "function": "_validated_tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.663e-05, + "cumulative_seconds": 0.0018647120000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 183, + "function": "encode", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 3.1916000000000004e-05, + "cumulative_seconds": 0.0018468310000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 205, + "function": "iterencode", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 0.001810416, + "cumulative_seconds": 0.001810416 + }, + { + "file": "python/workspace_curation.py", + "line": 170, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.542e-06, + "cumulative_seconds": 0.0017622920000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 232, + "function": "__init__", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 9.110700000000001e-05, + "cumulative_seconds": 0.001666993 + }, + { + "file": "python/workspace_service.py", + "line": 748, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.3248000000000002e-05, + "cumulative_seconds": 0.0016547500000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 37540, + "calls": 37540, + "self_seconds": 0.0016338400000000001, + "cumulative_seconds": 0.0016338400000000001 + }, + { + "file": "python/workspace_service.py", + "line": 778, + "function": "_epoch_page_identities", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.6097e-05, + "cumulative_seconds": 0.0016087500000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 166, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.291e-06, + "cumulative_seconds": 0.0015685 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 236, + "function": "_parse_field_descriptor", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 0.00036829900000000005, + "cumulative_seconds": 0.0015537180000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 348, + "function": "token", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 1.2165000000000001e-05, + "cumulative_seconds": 0.001510124 + }, + { + "file": "python/workspace_state_generation.py", + "line": 360, + "function": "_fresh_token", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.9041000000000003e-05, + "cumulative_seconds": 0.001481791 + }, + { + "file": "python/workspace_state_generation.py", + "line": 312, + "function": "_scope", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 1.4876000000000001e-05, + "cumulative_seconds": 0.0014350410000000002 + }, + { + "file": "python/workspace_explorer.py", + "line": 60, + "function": "protocol_binding_header", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 1.2042000000000001e-05, + "cumulative_seconds": 0.0013835000000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 282, + "function": "__and__", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 1.1124e-05, + "cumulative_seconds": 0.001319457 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 178, + "function": "restrict", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 9.629500000000001e-05, + "cumulative_seconds": 0.001308333 + }, + { + "file": "python/workspace_annotations.py", + "line": 34, + "function": "text", + "primitive_calls": 416, + "calls": 416, + "self_seconds": 0.000440176, + "cumulative_seconds": 0.0012498440000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 223, + "function": "attributes", + "primitive_calls": 1006, + "calls": 1006, + "self_seconds": 0.000390121, + "cumulative_seconds": 0.001217905 + }, + { + "file": "python/workspace_annotations.py", + "line": 40, + "function": "tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 7.2111e-05, + "cumulative_seconds": 0.0011247100000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 869, + "function": "_execute_command", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00023370200000000002, + "cumulative_seconds": 0.0011203720000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 61, + "function": "read", + "primitive_calls": 2720, + "calls": 2720, + "self_seconds": 0.000959097, + "cumulative_seconds": 0.0010828930000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 299, + "function": "loads", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 5.9896000000000004e-05, + "cumulative_seconds": 0.001076963 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 22, + "calls": 78, + "self_seconds": 5.8478000000000005e-05, + "cumulative_seconds": 0.001068251 + }, + { + "file": "python/workspace_service.py", + "line": 236, + "function": "source_scope", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.3665000000000004e-05, + "cumulative_seconds": 0.00104725 + }, + { + "file": "python/workspace_annotations.py", + "line": 42, + "function": "", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 5.6657e-05, + "cumulative_seconds": 0.001038922 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 285, + "function": "__getitem__", + "primitive_calls": 745, + "calls": 745, + "self_seconds": 0.00014253, + "cumulative_seconds": 0.001019633 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/decoder.py", + "line": 332, + "function": "decode", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 8.9196e-05, + "cumulative_seconds": 0.000981916 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 20373, + "calls": 20373, + "self_seconds": 0.0009458390000000001, + "cumulative_seconds": 0.0009793430000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/condition.py", + "line": 278, + "function": "make_condition", + "primitive_calls": 14, + "calls": 56, + "self_seconds": 0.00027003600000000003, + "cumulative_seconds": 0.000960207 + }, + { + "file": "python/workspace_annotations.py", + "line": 261, + "function": "filter_epoch_ids", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.955600000000001e-05, + "cumulative_seconds": 0.0009523330000000001 + }, + { + "file": "python/workspace_datastores.py", + "line": 192, + "function": "source_states", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 8.836e-06, + "cumulative_seconds": 0.000948293 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 456, + "calls": 456, + "self_seconds": 0.000248531, + "cumulative_seconds": 0.0008810030000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/decoder.py", + "line": 343, + "function": "raw_decode", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 0.0008460410000000001, + "cumulative_seconds": 0.0008460410000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/wrappers/response.py", + "line": 601, + "function": "get_json", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.126e-06, + "cumulative_seconds": 0.0008362920000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 839, + "function": "_write_bytes", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 4.7626e-05, + "cumulative_seconds": 0.0008345830000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 181, + "function": "loads", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.041e-06, + "cumulative_seconds": 0.0008183330000000001 + } + ], + "native_sql_calls": [ + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0007742500165477395 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0005213330150581896 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00025929202092811465 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004537919885478914 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00023424997925758362 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00036862504202872515 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0003762500127777457 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00014937500236555934 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00027541699819266796 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00023554201470687985 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005527909961529076 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.00138337496900931 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004224579897709191 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00020062498515471816 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004006249946542084 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00022650003666058183 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00041020900243893266 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0003804579610005021 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00013950001448392868 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00024399999529123306 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.00038479198701679707 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0003737080260179937 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0003434589598327875 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.0003375419764779508 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0003387089818716049 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00028745800955221057 + }, + { + "thread": "filter", + "sql_shape": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "seconds": 0.0004369160160422325 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`epoch_uuid`,`included`,`tags`,`review_state`,`revision`,`metadata_fingerprint` FROM `recording_workspace`.`curation` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))AND( ( (`epoch_uuid`='?') OR (", + "seconds": 0.0007845409563742578 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`dataset_uuid`,`created_at`,`artifact_sha256` FROM `recording_workspace`.`dataset_revision` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00028974999440833926 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.001720083993859589 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.000624708947725594 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00045970798237249255 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0001912500010803342 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.0002727499813772738 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0003328750026412308 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0006773329805582762 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0005508330068551004 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.0002952920040115714 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004585420247167349 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00024391704937443137 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00041437498293817043 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0005044999998062849 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00014483300037682056 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0002448330051265657 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00019770802464336157 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005259579629637301 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0015403329744003713 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00045495800441130996 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00028795795515179634 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005116669926792383 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00045954197412356734 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004956669872626662 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00037408299976959825 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00017891702009364963 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0003070419770665467 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0006083330372348428 + } + ], + "limits": "Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap." + }, + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": "const,const", + "rows": 20, + "filtered": 10.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.022153 + } + }, + "project_uuid": "69b6a7e7-762d-4adf-ad65-b1c3a8eff7f1", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.102921 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.02182 + } + }, + "project_uuid": "69b6a7e7-762d-4adf-ad65-b1c3a8eff7f1", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.175279 + }, + "seconds": 0.27823945798445493, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "workflow_peak_rss_before_durable_oracle_bytes": 173129728, + "durable_snapshot_verify_seconds": 0.03394283400848508, + "loaded_product_modules": { + "workspace_tree": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tree.py", + "workspace_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_predicates.py", + "workspace_cache_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_cache_lifecycle.py", + "workspace_metadata_objects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_metadata_objects.py", + "workspace_disk_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_disk_index.py", + "workspace_catalog_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_catalog_identity.py", + "recording_workspace": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/recording_workspace.py", + "workspace_recipes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_recipes.py", + "workspace_tree_code": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tree_code.py", + "workspace_service": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_service.py", + "workspace_tree_pages": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tree_pages.py", + "workspace_projects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_projects.py", + "workspace_mysql_profile": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_mysql_profile.py", + "workspace_native_mysql": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_native_mysql.py", + "workspace_mysql_runtime": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_mysql_runtime.py", + "workspace_storage": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_storage.py", + "workspace_diff": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_diff.py", + "workspace_protocol_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_protocol_identity.py", + "workspace_import_check": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_import_check.py", + "workspace_audit": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_audit.py", + "workspace_api": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_api.py", + "workspace_state_snapshot": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_state_snapshot.py", + "workspace_author_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_author_preferences.py", + "workspace_curation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_curation.py", + "workspace_annotations": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_annotations.py", + "workspace_shared_tag_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_shared_tag_index.py", + "workspace_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_paths.py", + "workspace_desktop_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_desktop_paths.py", + "workspace_startup_registry": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_startup_registry.py", + "workspace_explorer": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_explorer.py", + "workspace_datastores": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_datastores.py", + "workspace_suggestions": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_suggestions.py", + "workspace_tag_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tag_predicates.py", + "workspace_export_folder": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_export_folder.py", + "workspace_import_progress": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_import_progress.py", + "workspace_project_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_project_preferences.py", + "workspace_protocol_state": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_protocol_state.py", + "workspace_state_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_state_generation.py", + "workspace_project_servers": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_project_servers.py", + "workspace_launcher": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_launcher.py", + "workspace_app_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_app_routes.py", + "workspace_folder_browser": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_folder_browser.py", + "workspace_h5_inbox": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_h5_inbox.py", + "workspace_tag_exchange": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_tag_exchange.py", + "workspace_external_tags": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_external_tags.py", + "workspace_qc": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_qc.py", + "workspace_search": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_search.py", + "workspace_matlab_masks": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_matlab_masks.py", + "workspace_matlab_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_matlab_routes.py", + "workspace_mask_refresh": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_mask_refresh.py", + "workspace_matching_epochs": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_matching_epochs.py", + "workspace_candidate_exports": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_candidate_exports.py", + "workspace_backup_scheduler": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_backup_scheduler.py", + "workspace_recovery_store": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_recovery_store.py", + "workspace_recovery_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_recovery_generation.py", + "workspace_annotation_preparation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_annotation_preparation.py", + "workspace_native_tag_lookup": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_native_tag_lookup.py", + "workspace_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_lifecycle.py", + "workspace_native_tag_filter": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq/python/workspace_native_tag_filter.py" + }, + "owned_native_runtime_stopped": true, + "source_inventory_after": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "d81d9c5e03e62024c30474612596ee3fec2753a745e39c2db005010c85b8ffff", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "b70fe1d82baa6ab40901d17e49ef8946297379a6d1adc3929a9cb979ae947e5a", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_empty_blocks.py": "ff0973074a72cf110b90dd8f76f032d5016315bbb21f84569e9fa701b11a7d88", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3cf4ab9a1b5db849600c2716e9026cfb3d0817389f240d5d9cee9dbfe0b7922d", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "a7bc5ddb5f153aacb23c13eb11b1ca14515ddcd12526567f41e49252931ddf96", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "9bf32c59a9847f5b7231987348fd54ad1f6eec4773323b125ae34d1239632fbb", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "8cb336a98cf2f487a3bf30db1ddc6ad5db1081018cee394d2690dffa04f8c1bd", + "python/workspace_native_tag_lookup.py": "ae8d7fd3b2f80d56078777b03de4189b648f536ead1ca1225ad6c72a7c59a466", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "68e142d6008248c67310462b692b130f0951a87a802187f59d0e6302a78073fc", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "source_unchanged": true, + "harness_unchanged": true, + "seconds": 11.342676208994817, + "finished_at": "2026-09-30T15:39:05.151038+00:00", + "peak_rss_bytes": 173129728, + "passed": true +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-100000.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-100000.json new file mode 100644 index 0000000..6236c41 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-100000.json @@ -0,0 +1,3307 @@ +{ + "scope": "Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy.\n\nEvery project/database is disposable. Acquisition metadata is synthetic; actual\nMySQL, triggers, Flask routes, derived indexes and each version's save hooks\nare used. Native SQL commits are checked immediately; any background recovery\nmirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude\noracle work, and do not model browser concurrency/rendering. Sequential bundle\ntimes are sums of their separately measured requests. Profiles are separate.\n", + "epochs": 100000, + "profiles": 3, + "tags_per_annotation": 5, + "protocols": 2, + "samples": 5, + "source_root": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI", + "source_inventory_before": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "98e5ddf9f5ea388f8697f2c5ea4e176aaf860450e78e2993c0f576ac164e11b5", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "4c586415a445d806ffe8d64d74f4d53d6d453be6fdcb2b4812da49f69a4525a2", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7afc6c297770800fb90e148ffeb4ad3d5c24c8e84f5a788094f3246f59f97782", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6286df8eb8ea15f0c2c558a9a42c291167277cb5654ec4dd132ad739e96733b1", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "6587dcb57e94489175dad26bbbfaa9142170f7eb1b947fe7b3becf40707e11cf", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "9f198eb78c0ccc44dfdd4aebd44c0dd890482d6020b0164c5acce4955e46f5e6", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "a75c94ce4c2a5863fb2bf5d79c6abaf4304fb7aa90726d89d80a9e69114d5710", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "3f5ec51667618b9e0a215f6371dd22a9e1502afd54166da0efb9b677045d4216", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "35a10441d0ba59e43c59ad564879b2b73eccc29cd19a2558e3eaf8db1a9f5782", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "fixture_module": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py", + "harness_sha256": "a2b5e70861826936fdb4c9d6a5c76efd7645486ad5ce05e1482e3e6aab694fde", + "started_at": "2026-09-30T15:02:54.636220+00:00", + "release_ready": false, + "operations": { + "first10_revision_preflight": { + "samples_seconds": [ + 0.011627708037849516, + 0.09122683299938217, + 0.007156417006626725, + 0.040542583039496094, + 0.006898041989188641 + ], + "p50_seconds": 0.011627708037849516, + "p95_seconds": 0.09122683299938217, + "p99_seconds": 0.09122683299938217, + "maximum_seconds": 0.09122683299938217, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 245961, + "Questions": 130 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + } + ] + }, + "first10_save": { + "samples_seconds": [ + 0.04437404201598838, + 0.020467541995458305, + 0.02093420800520107, + 0.020763959037140012, + 0.018009499995969236 + ], + "p50_seconds": 0.020763959037140012, + "p95_seconds": 0.04437404201598838, + "p99_seconds": 0.04437404201598838, + "maximum_seconds": 0.04437404201598838, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 18600, + "Questions": 36 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12424, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + } + ] + }, + "second10_revision_preflight": { + "samples_seconds": [ + 0.006863999995402992, + 0.005781583022326231, + 0.006198541959747672, + 0.006267749995458871, + 0.026554333977401257 + ], + "p50_seconds": 0.006267749995458871, + "p95_seconds": 0.026554333977401257, + "p99_seconds": 0.026554333977401257, + "maximum_seconds": 0.026554333977401257, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + } + ] + }, + "second10_save": { + "samples_seconds": [ + 0.027478916046675295, + 0.01964816596591845, + 0.019734667032025754, + 0.025464750011451542, + 0.02433695795480162 + ], + "p50_seconds": 0.02433695795480162, + "p95_seconds": 0.027478916046675295, + "p99_seconds": 0.027478916046675295, + "maximum_seconds": 0.027478916046675295, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12436, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + } + ] + }, + "filter20": { + "samples_seconds": [ + 0.9843111250083894, + 0.11473174998536706, + 0.13281304098200053, + 0.12448295799549669, + 0.1226571670267731 + ], + "p50_seconds": 0.12448295799549669, + "p95_seconds": 0.9843111250083894, + "p99_seconds": 0.9843111250083894, + "maximum_seconds": 0.9843111250083894, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 156852, + "Questions": 83 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + }, + { + "Bytes_sent": 396264, + "Questions": 183 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + } + ] + }, + "cell_save": { + "samples_seconds": [ + 0.008944916015025228, + 0.008186708961147815, + 0.008591292018536478, + 0.007889083004556596, + 0.008863541996106505 + ], + "p50_seconds": 0.008591292018536478, + "p95_seconds": 0.008944916015025228, + "p99_seconds": 0.008944916015025228, + "maximum_seconds": 0.008944916015025228, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4166, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + } + ] + }, + "filter_cell100": { + "samples_seconds": [ + 0.15682324999943376, + 0.1472697500139475, + 0.15188124997075647, + 0.1603592080064118, + 0.16214675002265722 + ], + "p50_seconds": 0.15682324999943376, + "p95_seconds": 0.16214675002265722, + "p99_seconds": 0.16214675002265722, + "maximum_seconds": 0.16214675002265722, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + } + ] + }, + "filter_cell_and_epoch10": { + "samples_seconds": [ + 0.11638466699514538, + 0.13077333301771432, + 0.1285252090310678, + 0.12458279100246727, + 0.11700779100647196 + ], + "p50_seconds": 0.12458279100246727, + "p95_seconds": 0.13077333301771432, + "p99_seconds": 0.13077333301771432, + "maximum_seconds": 0.13077333301771432, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + } + ] + }, + "remove_first10_revision_preflight": { + "samples_seconds": [ + 0.006347040995024145, + 0.006440584023948759, + 0.0074722919962368906, + 0.006093290983699262, + 0.007031665998511016 + ], + "p50_seconds": 0.006440584023948759, + "p95_seconds": 0.0074722919962368906, + "p99_seconds": 0.0074722919962368906, + "maximum_seconds": 0.0074722919962368906, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + } + ] + }, + "remove_first10_save": { + "samples_seconds": [ + 0.019374625000637025, + 0.02045441698282957, + 0.021038750011939555, + 0.019824667018838227, + 0.017425708007067442 + ], + "p50_seconds": 0.019824667018838227, + "p95_seconds": 0.021038750011939555, + "p99_seconds": 0.021038750011939555, + "maximum_seconds": 0.021038750011939555, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12424, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + } + ] + }, + "filter_hierarchy_after_epoch_remove": { + "samples_seconds": [ + 0.10092024999903515, + 0.1075972500257194, + 0.11051483399933204, + 0.12653983401833102, + 0.10249387501971796 + ], + "p50_seconds": 0.1075972500257194, + "p95_seconds": 0.12653983401833102, + "p99_seconds": 0.12653983401833102, + "maximum_seconds": 0.12653983401833102, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + } + ] + }, + "filter_remaining10": { + "samples_seconds": [ + 0.11686000000918284, + 0.11886008305009454, + 0.12619370798347518, + 0.11449816601816565, + 0.1236068339785561 + ], + "p50_seconds": 0.11886008305009454, + "p95_seconds": 0.12619370798347518, + "p99_seconds": 0.12619370798347518, + "maximum_seconds": 0.12619370798347518, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + } + ] + }, + "remove_second10_revision_preflight": { + "samples_seconds": [ + 0.009842916973866522, + 0.010070999967865646, + 0.009961250005289912, + 0.010147833032533526, + 0.006309708987828344 + ], + "p50_seconds": 0.009961250005289912, + "p95_seconds": 0.010147833032533526, + "p99_seconds": 0.010147833032533526, + "maximum_seconds": 0.010147833032533526, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + } + ] + }, + "remove_second10_save": { + "samples_seconds": [ + 0.01778425002703443, + 0.01926620799349621, + 0.02287991699995473, + 0.018311958003323525, + 0.01896583300549537 + ], + "p50_seconds": 0.01896583300549537, + "p95_seconds": 0.02287991699995473, + "p99_seconds": 0.02287991699995473, + "maximum_seconds": 0.02287991699995473, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12436, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + } + ] + }, + "filter_after_all_epoch_removals": { + "samples_seconds": [ + 0.10538366599939764, + 0.10673487500753254, + 0.1089959159726277, + 0.10726999997859821, + 0.10814420797396451 + ], + "p50_seconds": 0.10726999997859821, + "p95_seconds": 0.1089959159726277, + "p99_seconds": 0.1089959159726277, + "maximum_seconds": 0.1089959159726277, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + } + ] + }, + "remove_cell_save": { + "samples_seconds": [ + 0.008432624978013337, + 0.007472749974112958, + 0.008027833013329655, + 0.0073897080146707594, + 0.00871045800158754 + ], + "p50_seconds": 0.008027833013329655, + "p95_seconds": 0.00871045800158754, + "p99_seconds": 0.00871045800158754, + "maximum_seconds": 0.00871045800158754, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4166, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + } + ] + }, + "filter_after_cell_removal": { + "samples_seconds": [ + 0.10941074998117983, + 0.10573266696883366, + 0.10774483397835866, + 0.1067830000538379, + 0.11562345898710191 + ], + "p50_seconds": 0.10774483397835866, + "p95_seconds": 0.11562345898710191, + "p99_seconds": 0.11562345898710191, + "maximum_seconds": 0.11562345898710191, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + } + ] + }, + "tag10_then10_filter20_http_total": { + "samples_seconds": [ + 1.0746557911043055, + 0.2518558739684522, + 0.18683687498560175, + 0.2175220000790432, + 0.19845600094413385 + ], + "p50_seconds": 0.2175220000790432, + "p95_seconds": 1.0746557911043055, + "p99_seconds": 1.0746557911043055, + "maximum_seconds": 1.0746557911043055, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "cell_tag_then_cell_filter_http_total": { + "samples_seconds": [ + 0.16576816601445898, + 0.1554564589750953, + 0.16047254198929295, + 0.1682482910109684, + 0.17101029201876372 + ], + "p50_seconds": 0.16576816601445898, + "p95_seconds": 0.17101029201876372, + "p99_seconds": 0.17101029201876372, + "maximum_seconds": 0.17101029201876372, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "first10_selected_action_http_total": { + "samples_seconds": [ + 0.056001750053837895, + 0.11169437499484047, + 0.028090625011827797, + 0.061306542076636106, + 0.024907541985157877 + ], + "p50_seconds": 0.056001750053837895, + "p95_seconds": 0.11169437499484047, + "p99_seconds": 0.11169437499484047, + "maximum_seconds": 0.11169437499484047, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "second10_selected_action_http_total": { + "samples_seconds": [ + 0.034342916042078286, + 0.025429748988244683, + 0.025933208991773427, + 0.031732500006910414, + 0.050891291932202876 + ], + "p50_seconds": 0.031732500006910414, + "p95_seconds": 0.050891291932202876, + "p99_seconds": 0.050891291932202876, + "maximum_seconds": 0.050891291932202876, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "autocomplete_cold_diagnostic": { + "samples_seconds": [ + 10.202606874983758 + ], + "p50_seconds": 10.202606874983758, + "p95_seconds": 10.202606874983758, + "p99_seconds": 10.202606874983758, + "maximum_seconds": 10.202606874983758, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 214986, + "Questions": 89 + } + ] + }, + "autocomplete_warm_diagnostic": { + "samples_seconds": [ + 9.474194333015475 + ], + "p50_seconds": 9.474194333015475, + "p95_seconds": 9.474194333015475, + "p99_seconds": 9.474194333015475, + "maximum_seconds": 9.474194333015475, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 214986, + "Questions": 89 + } + ] + }, + "same_server_native_reuse_filter20": { + "samples_seconds": [ + 0.1438881250214763 + ], + "p50_seconds": 0.1438881250214763, + "p95_seconds": 0.1438881250214763, + "p99_seconds": 0.1438881250214763, + "maximum_seconds": 0.1438881250214763, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 134746, + "Questions": 57 + } + ] + } + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 33334 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 66666 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 66667 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "page_cells": true, + "target_specification": "tag10_then10_filter20_and_cell_epoch_hierarchy", + "baseline_harness_sha256": "272fe050c8762ed4ea45bd013e236e8723d8fe46f5e7e293c58e2edf1fd52ddc", + "mysql_version": "8.4.2", + "seed_seconds": 115.08456225000555, + "seed_checkpoint_seconds": 14.813979834027123, + "native_lookup_startup_preparation": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "2aa92db9-6472-4c39-9292-5794937593db", + "reused": false, + "phase": "complete", + "seconds": 0.173335 + }, + "selected_epoch_uuids": { + "first10": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5" + ], + "second10": [ + "ad573668-6512-6e55-649e-cb23ae1d4888", + "16dc368a-89b4-28b2-4854-84313ba67a39", + "37834f2f-2576-2f23-e1f7-4a531cbe445d", + "454f63ac-30c8-3229-97ef-025edff6abd2", + "5ef6fdf3-2513-aa7c-d11f-72beccf132b9", + "1253e937-3e78-1b75-0026-6caa55150e08", + "482d9673-cfee-5de3-91f9-7fde4d1c84f9", + "3346f2bb-f6c3-4bd2-dbe2-8bd1bb657d0e", + "9537f32e-c759-9e1a-e953-af6c9f929fe7", + "0fd42b3f-73c4-48b3-4940-b339f87d07ad" + ], + "cell": "3bb78535-cc95-55ff-19fe-3556aaa41c78", + "cell_children": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5", + "4a44dc15-3642-04a8-0fe8-0e9039455cc1", + "4fc82b26-aecb-47d2-868c-4efbe3581732", + "6b51d431-df5d-7f14-1cbe-ceccf79edf3d", + "3fdba35f-04dc-8c46-2986-c992bcf87554", + "8527a891-e224-1369-50ff-32ca212b45bc", + "e629fa65-98d7-3276-8f7c-726b4b621285", + "b17ef6d1-9c7a-5b1e-e83b-907c595526dc", + "4523540f-1504-cd17-100c-4835e85b7eef", + "4ec9599f-c203-d176-a301-536c2e091a19", + "9400f1b2-1cb5-27d7-fa3d-3eabba93557a", + "f5ca38f7-48a1-d6ea-f726-b8a42fb575c3", + "6f4b6612-125f-b3a0-daec-d2799dfd6c9c", + "785f3ec7-eb32-f30b-90cd-0fcf3657d388", + "535fa30d-7e25-dd8a-49f1-536779734ec8", + "c2356069-e9d1-e79c-a924-378153cfbbfb", + "b7a56873-cd77-1f2c-446d-369b649430b6", + "5f9c4ab0-8cac-7457-e911-1a30e4664920", + "670671cd-9740-4156-226e-507973f2ab83", + "59e19706-d51d-39f6-6711-c2653cd7eb12", + "35135aaa-6cc2-3891-b40c-b3f378c53a17", + "624b60c5-8c9d-8bfb-6ff1-886c2fd605d2", + "eb1e33e8-a81b-697b-7585-5af6bfcdbcbf", + "e29c9c18-0c62-79b0-b02a-bd6a1801c7c0", + "c6f3ac57-944a-5314-90cd-39902d0f7777", + "86e50149-6586-6131-2a9e-0b35558d84f6", + "9f14025a-f006-5b30-e47e-23ebb3b491d3", + "76a50887-d8f1-c2e9-3017-55428990ad81", + "7a61b537-01be-fdae-0eee-ffaecc73f14e", + "aea92132-c4cb-eb26-3e6a-c2bf6c183b5d", + "0b918943-df09-62bc-7a18-24c0555a3893", + "d59eced1-ded0-7f84-c145-592f65bdf854", + "3d914f93-48c9-cc0f-f8a7-9716700b9fcd", + "73475cb4-0a56-8e8d-a8a0-45ced110137e", + "44cb730c-4204-80a0-477b-505ae68af508", + "71ee45a3-c0db-9a98-65f7-313dd3372cf6", + "811786ad-1ae7-4adf-dd20-dd0372abaaeb", + "25fc0e70-96fc-6537-1820-2dc30b0c580b", + "31489056-e091-6d59-fe3a-dd79e63f095a", + "98010bd9-270f-9b10-0b62-14a21754fd33", + "0e17daca-5f3e-175f-448b-acace3bc0da4", + "1a656259-0ef1-9d10-45d0-6c4055742d38", + "031b4af5-197e-c30a-926f-48cf40e11a7d", + "41cfc0d1-f2d1-27b0-4555-b7246d84019b", + "2858dcd1-057d-3eae-7f7d-5f782167e24b", + "2fca346d-b656-1871-02ce-806ac732e06a", + "02d20bbd-7e39-4ad5-999a-4cebabac9619", + "7688b6ef-5255-5962-d008-fff894223582", + "c837649c-ce43-f272-9138-e72cc3152070", + "6208ef0f-7750-c111-548c-f90b6ea1d0d0", + "3e1e967e-9b79-3e90-8f8e-ae83c74dba9b", + "39fa9ec1-90ee-e7b6-f4df-f1100d6343e1", + "d029fa3a-95e1-74a1-9934-857f535eb942", + "81b8a03f-97e8-787c-53fe-1a86bda042b6", + "da4ea2a5-506f-2693-eae1-90d9360a1f31", + "a68b412c-4282-555f-1554-6cf6e1fc4289", + "108c995b-953c-8a35-5611-03e2014cf828", + "3ada92f2-8b4c-eda3-8562-ebf047c6ff05", + "49d180ec-f561-3281-9571-bf39d9b7b342", + "a21855da-08cb-102d-1d21-7c53dc5824a3", + "c75cb66a-e28d-8ebc-6ede-d002c28a8ba0", + "ff5a1ae0-12af-a5d4-c889-c50ad427aaf5", + "7f2253d7-e228-b22a-08bd-a1f09c516f6f", + "87226162-0421-7edd-b39e-7df969e0698a", + "96061e92-f58e-4bdc-dee7-3df36183fe3a", + "eb624dbe-56eb-6620-ae62-080c10a273ca", + "f369cb89-fc62-7e66-8987-007d121ed1ea", + "f74efabe-f12e-a619-e30b-79bddef89cff", + "a88a7902-cb4e-f697-ba0b-6759c50e8c10", + "349c4120-1b62-db85-1192-665c504b350f", + "98a3ab7c-340e-8a03-3e7b-37b6ef942875", + "48449a14-a4ff-7d79-bb7a-1b6f3d488eba", + "5316ca1c-5ddc-a8e6-cecc-fce58f3b8540", + "a46e3763-2fa6-ca51-a13f-e39a567b3c23", + "bbb965ab-0c80-d653-8cf2-184babad2a56", + "44c8031c-b036-a735-0d8b-9b8603af662a", + "b4944c6f-f08d-c6f4-3da2-e9c824669b7d", + "434c9b5a-e514-646b-bd91-b50032ca579e", + "bdd2d3af-3a5a-1213-497d-4f1f7bfcda89", + "8b940be7-fb78-aaa6-b656-7dd7a3987996", + "cd70bea0-23f7-52a0-564a-bb6ed08d42c1", + "69f59c27-3b6e-669a-c32a-6dd5e1b2cb63", + "1da51b8d-8ff9-8f6a-48f8-0ae79fe3ca6c", + "82416496-09f8-8ccd-2a0a-5b233a07a538", + "6e400187-1c0c-f27c-7634-ef1dc478408f", + "e3d6c4d4-599e-0088-2384-ca981ee287ed", + "ad48ff99-415b-2f00-7dc3-5b7eb553fd1e", + "7b1a278f-5abe-8e9d-a907-fc9c29dfd432", + "d6d824ab-ba4a-fde8-1129-c71dea75b810", + "29db0c67-82db-d500-0559-ef4d9e953e30", + "8c1f1046-219d-dd21-6a02-3f792356ddf1" + ] + }, + "backup_receipts": [ + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 1, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 2, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 2, + "last_error": null, + "last_success": "2026-09-30T15:05:40.003731+00:00", + "pending": true, + "requested_sequence": 3, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 2, + "last_error": null, + "last_success": "2026-09-30T15:05:40.003731+00:00", + "pending": true, + "requested_sequence": 4, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 2, + "last_error": null, + "last_success": "2026-09-30T15:05:40.003731+00:00", + "pending": true, + "requested_sequence": 5, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 2, + "last_error": null, + "last_success": "2026-09-30T15:05:40.003731+00:00", + "pending": true, + "requested_sequence": 6, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 7, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 8, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 9, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 10, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 11, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 12, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 13, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 14, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 15, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 16, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 17, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 18, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 19, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 6, + "last_error": null, + "last_success": "2026-09-30T15:05:42.758327+00:00", + "pending": true, + "requested_sequence": 20, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 21, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 22, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 23, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 24, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 25, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 26, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 27, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 28, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 29, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 20, + "last_error": null, + "last_success": "2026-09-30T15:05:47.971642+00:00", + "pending": true, + "requested_sequence": 30, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_first10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:05:52.972148+00:00", + "pending": true, + "requested_sequence": 31, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_second10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:05:52.972148+00:00", + "pending": true, + "requested_sequence": 32, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_first10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:06:13.433464+00:00", + "pending": true, + "requested_sequence": 33, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_second10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:06:13.433464+00:00", + "pending": true, + "requested_sequence": 34, + "running": false, + "status": "pending" + }, + "database": "committed" + } + } + ], + "preparation_index_seconds": 0, + "lookup_mode": "persistent_native_sql_no_post_seed_tag_cache_preparation", + "bundle_definitions": { + "tag10_then10_filter20_http_total": [ + "first10_revision_preflight", + "first10_save", + "second10_revision_preflight", + "second10_save", + "filter20" + ], + "cell_tag_then_cell_filter_http_total": [ + "cell_save", + "filter_cell100" + ], + "first10_selected_action_http_total": [ + "first10_revision_preflight", + "first10_save" + ], + "second10_selected_action_http_total": [ + "second10_revision_preflight", + "second10_save" + ] + }, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:06:18.387002+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 5.976898541965056 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 4.200603792036418 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 5.332792375003919 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 4.116656041005626 + } + ] + }, + "autocomplete_query_plans": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY,by_tag", + "key": "PRIMARY", + "key_len": "38", + "ref": "const", + "rows": 613093, + "filtered": 100.0, + "Extra": "Using index; Using filesort" + } + ] + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "explain": [ + { + "id": 1, + "select_type": "PRIMARY", + "table": "", + "partitions": null, + "type": "ALL", + "possible_keys": null, + "key": null, + "key_len": null, + "ref": null, + "rows": 183927, + "filtered": 100.0, + "Extra": null + }, + { + "id": 1, + "select_type": "PRIMARY", + "table": "a", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "111", + "ref": "const,func", + "rows": 1, + "filtered": 5.0, + "Extra": "Using where" + }, + { + "id": 2, + "select_type": "DERIVED", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY,by_tag", + "key": "PRIMARY", + "key_len": "38", + "ref": "const", + "rows": 613093, + "filtered": 30.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "filter20_cpu_profile": { + "top_functions": [ + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 313, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.4170000000000006e-06, + "cumulative_seconds": 0.374428792 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 159, + "function": "request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.958e-06, + "cumulative_seconds": 0.374386333 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1163, + "function": "get", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.375000000000001e-06, + "cumulative_seconds": 0.373476542 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/testing.py", + "line": 204, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.4083e-05, + "cumulative_seconds": 0.373470167 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1062, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.793e-06, + "cumulative_seconds": 0.37316512500000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 984, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0249000000000001e-05, + "cumulative_seconds": 0.37314945800000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1230, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.2624000000000001e-05, + "cumulative_seconds": 0.3726995 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1529, + "function": "__call__", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.334000000000001e-06, + "cumulative_seconds": 0.37266475000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1479, + "function": "wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.5376e-05, + "cumulative_seconds": 0.37265841600000005 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 904, + "function": "full_dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.126e-06, + "cumulative_seconds": 0.37206475 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 879, + "function": "dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.00010283200000000001, + "cumulative_seconds": 0.37178904100000004 + }, + { + "file": "python/workspace_api.py", + "line": 716, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000158837, + "cumulative_seconds": 0.371678542 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 27, + "calls": 38, + "self_seconds": 3.0666e-05, + "cumulative_seconds": 0.185190878 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 249, + "function": "native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.0250000000000003e-05, + "cumulative_seconds": 0.185127292 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 268, + "function": "_native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.6667e-05, + "cumulative_seconds": 0.16585575000000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 311, + "function": "native_context", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 7.0245e-05, + "cumulative_seconds": 0.16577804200000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 207, + "function": "_metadata_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 0.017342542000000002, + "cumulative_seconds": 0.15863058300000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 22, + "calls": 4058, + "self_seconds": 0.001319663, + "cumulative_seconds": 0.14160387700000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 212, + "function": "", + "primitive_calls": 18, + "calls": 18, + "self_seconds": 2.7706000000000002e-05, + "cumulative_seconds": 0.141277457 + }, + { + "file": "python/workspace_service.py", + "line": 748, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.0010381280000000001, + "cumulative_seconds": 0.138147084 + }, + { + "file": "python/workspace_service.py", + "line": 778, + "function": "_epoch_page_identities", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.008510140000000001, + "cumulative_seconds": 0.137031375 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 55, + "function": "_epoch_query_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 0.102637528, + "cumulative_seconds": 0.130549292 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 132, + "function": "__enter__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 2.876e-06, + "cumulative_seconds": 0.10969495800000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 261, + "function": "filter_epoch_ids", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.023571786, + "cumulative_seconds": 0.105705084 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 141, + "function": "__exit__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 5.416e-06, + "cumulative_seconds": 0.07543862500000001 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 8, + "function": "matching", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.047434952, + "cumulative_seconds": 0.0730085 + }, + { + "file": "python/workspace_annotations.py", + "line": 295, + "function": "for_epochs", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.00010728200000000001, + "cumulative_seconds": 0.035757167 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 304, + "function": "traced_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000255777, + "cumulative_seconds": 0.033613458 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 412, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000147334, + "cumulative_seconds": 0.032831003000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 402, + "function": "_execute_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000145164, + "cumulative_seconds": 0.032476752000000005 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 150, + "function": "execute", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.016100000000001e-05, + "cumulative_seconds": 0.032024374 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 332, + "function": "_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.8291e-05, + "cumulative_seconds": 0.031495709000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 575, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 8.983e-05, + "cumulative_seconds": 0.030965087000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 535040, + "calls": 535040, + "self_seconds": 0.029391985000000002, + "cumulative_seconds": 0.029391985000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 851, + "function": "_read_query_result", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.4422e-05, + "cumulative_seconds": 0.029344170000000003 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1288, + "function": "read", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 8.8255e-05, + "cumulative_seconds": 0.029244248 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 128, + "function": "deepcopy", + "primitive_calls": 78, + "calls": 17170, + "self_seconds": 0.019775887000000002, + "cumulative_seconds": 0.026320795 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 201, + "function": "_deepcopy_list", + "primitive_calls": 62, + "calls": 102, + "self_seconds": 0.000301189, + "cumulative_seconds": 0.026185620000000003 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 227, + "function": "_deepcopy_dict", + "primitive_calls": 1242, + "calls": 1284, + "self_seconds": 0.002786677, + "cumulative_seconds": 0.024226512000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 763, + "function": "_read_packet", + "primitive_calls": 765, + "calls": 765, + "self_seconds": 0.001309718, + "cumulative_seconds": 0.020606641000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 101, + "function": "_rows", + "primitive_calls": 46, + "calls": 46, + "self_seconds": 6.8374e-05, + "cumulative_seconds": 0.019305502000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 197, + "function": "response_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.5752e-05, + "cumulative_seconds": 0.019156126000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 233, + "function": "_attest_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 7.8791e-05, + "cumulative_seconds": 0.01911475 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 813, + "function": "_read_bytes", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.0005736410000000001, + "cumulative_seconds": 0.017317151 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.000242761, + "cumulative_seconds": 0.016664344 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/socket.py", + "line": 704, + "function": "readinto", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 0.00010028000000000001, + "cumulative_seconds": 0.016421583 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1299, + "function": "recv_into", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 8.8368e-05, + "cumulative_seconds": 0.016270255 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 869, + "function": "to_dicts", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.4788e-05, + "cumulative_seconds": 0.016210542 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1157, + "function": "read", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 4.7793e-05, + "cumulative_seconds": 0.016172626000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 0.016120626000000002, + "cumulative_seconds": 0.016120626000000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 34, + "function": "_exact_equal", + "primitive_calls": 22, + "calls": 14072, + "self_seconds": 0.0038657690000000002, + "cumulative_seconds": 0.014416209000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 1231, + "function": "cursor", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.4924e-05, + "cumulative_seconds": 0.014076628 + }, + { + "file": "python/workspace_service.py", + "line": 845, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.012475625, + "cumulative_seconds": 0.012475625 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1370, + "function": "_read_result_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.1754e-05, + "cumulative_seconds": 0.012389460000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 42, + "function": "", + "primitive_calls": 6012, + "calls": 16026, + "self_seconds": 0.008119805, + "cumulative_seconds": 0.011268288000000001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 134, + "function": "_active_ddl_guard", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 5.0499000000000006e-05, + "cumulative_seconds": 0.01104571 + }, + { + "file": "python/workspace_service.py", + "line": 797, + "function": "", + "primitive_calls": 100001, + "calls": 100001, + "self_seconds": 0.009490819000000001, + "cumulative_seconds": 0.009490819000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1416, + "function": "_read_rowdata_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00038105500000000004, + "cumulative_seconds": 0.009312415000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 173, + "function": "_rows", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.3291e-05, + "cumulative_seconds": 0.008443 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/__init__.py", + "line": 138, + "function": "jsonify", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.332000000000001e-06, + "cumulative_seconds": 0.007500791000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 189, + "function": "response", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.6874e-05, + "cumulative_seconds": 0.0074843340000000005 + }, + { + "file": "python/workspace_api.py", + "line": 61, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.5209e-05, + "cumulative_seconds": 0.0074175840000000005 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 100027, + "calls": 100027, + "self_seconds": 0.007347353, + "cumulative_seconds": 0.007347353 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1429, + "function": "_read_row_from_packet", + "primitive_calls": 428, + "calls": 428, + "self_seconds": 0.0009690370000000001, + "cumulative_seconds": 0.007011843 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 68, + "function": "", + "primitive_calls": 21, + "calls": 21, + "self_seconds": 0.0059070400000000006, + "cumulative_seconds": 0.0059070400000000006 + }, + { + "file": "python/workspace_api.py", + "line": 62, + "function": "browser_safe", + "primitive_calls": 1, + "calls": 9641, + "self_seconds": 0.0031328690000000004, + "cumulative_seconds": 0.0056478330000000005 + }, + { + "file": "python/workspace_api.py", + "line": 66, + "function": "", + "primitive_calls": 1, + "calls": 1363, + "self_seconds": 0.0014191730000000001, + "cumulative_seconds": 0.005645458000000001 + }, + { + "file": "python/workspace_api.py", + "line": 68, + "function": "", + "primitive_calls": 2, + "calls": 102, + "self_seconds": 0.00021272200000000001, + "cumulative_seconds": 0.005634167000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 185, + "function": "_metadata", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 8.4875e-05, + "cumulative_seconds": 0.005598292 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 205717, + "calls": 205719, + "self_seconds": 0.005549391000000001, + "cumulative_seconds": 0.005549765000000001 + }, + { + "file": "python/workspace_explorer.py", + "line": 60, + "function": "protocol_binding_header", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 2.2667e-05, + "cumulative_seconds": 0.004394084 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/converters.py", + "line": 166, + "function": "convert_datetime", + "primitive_calls": 144, + "calls": 144, + "self_seconds": 0.003984993, + "cumulative_seconds": 0.004224045 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 100008, + "calls": 100008, + "self_seconds": 0.0041956020000000005, + "cumulative_seconds": 0.0041956020000000005 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 38, + "function": "walk", + "primitive_calls": 1, + "calls": 2, + "self_seconds": 0.001548792, + "cumulative_seconds": 0.0037413750000000003 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 68, + "function": "", + "primitive_calls": 10, + "calls": 10, + "self_seconds": 1.0292e-05, + "cumulative_seconds": 0.003726042 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 44, + "function": "", + "primitive_calls": 2040, + "calls": 2040, + "self_seconds": 0.000484992, + "cumulative_seconds": 0.003606039 + }, + { + "file": "python/workspace_state_generation.py", + "line": 125, + "function": "_observer_status", + "primitive_calls": 8, + "calls": 8, + "self_seconds": 3.1464e-05, + "cumulative_seconds": 0.003434084 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 106471, + "calls": 106471, + "self_seconds": 0.003273446, + "cumulative_seconds": 0.003273446 + }, + { + "file": "python/workspace_state_generation.py", + "line": 107, + "function": "_ddl", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 3.8205000000000004e-05, + "cumulative_seconds": 0.003112208 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1448, + "function": "_get_descriptions", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00037153500000000004, + "cumulative_seconds": 0.002979207 + }, + { + "file": "python/workspace_state_generation.py", + "line": 115, + "function": "_triggers", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.791e-06, + "cumulative_seconds": 0.0028592910000000003 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 101, + "function": "selected", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.7252e-05, + "cumulative_seconds": 0.002837 + }, + { + "file": "python/workspace_curation.py", + "line": 170, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.5624e-05, + "cumulative_seconds": 0.0026332910000000003 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 0.002589833, + "cumulative_seconds": 0.002589833 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 163, + "function": "read_length_coded_string", + "primitive_calls": 2712, + "calls": 2712, + "self_seconds": 0.0008559580000000001, + "cumulative_seconds": 0.0025305230000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 898, + "function": "", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 5.4031000000000005e-05, + "cumulative_seconds": 0.002105 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 183, + "function": "dumps", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 4.0372000000000006e-05, + "cumulative_seconds": 0.0020357910000000003 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 183, + "function": "encode", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.8629000000000003e-05, + "cumulative_seconds": 0.0019757100000000003 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 205, + "function": "iterencode", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 0.0019436660000000001, + "cumulative_seconds": 0.0019436660000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 899, + "function": "", + "primitive_calls": 86, + "calls": 86, + "self_seconds": 0.00035072, + "cumulative_seconds": 0.0017950870000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 166, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.917e-06, + "cumulative_seconds": 0.0017245420000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 195, + "function": "_chips", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 3.8292000000000005e-05, + "cumulative_seconds": 0.0017142510000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 232, + "function": "__init__", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 9.221e-05, + "cumulative_seconds": 0.0016251290000000001 + }, + { + "file": "python/workspace_service.py", + "line": 236, + "function": "source_scope", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 6.7618e-05, + "cumulative_seconds": 0.0015764160000000002 + }, + { + "file": "python/workspace_annotations.py", + "line": 188, + "function": "_validated_tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.0371e-05, + "cumulative_seconds": 0.001572087 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 869, + "function": "_execute_command", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00045425, + "cumulative_seconds": 0.001518337 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 236, + "function": "_parse_field_descriptor", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 0.00035320400000000003, + "cumulative_seconds": 0.001511043 + }, + { + "file": "python/workspace_datastores.py", + "line": 192, + "function": "source_states", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.4749000000000003e-05, + "cumulative_seconds": 0.0014340000000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 282, + "function": "__and__", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 1.2125e-05, + "cumulative_seconds": 0.001374666 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 178, + "function": "restrict", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 0.000107409, + "cumulative_seconds": 0.001362541 + } + ], + "native_sql_calls": [ + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.001239582954440266 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003942079492844641 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00023616600083187222 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004265829920768738 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0003481670282781124 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003493750118650496 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0004118339857086539 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00013762497110292315 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00021129200467839837 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00018354097846895456 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005306670209392905 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0013821249594911933 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004562920075841248 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.0001866249949671328 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0003940830356441438 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002472499618306756 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00034708401653915644 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00029858300695195794 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00013683299766853452 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00021649996051564813 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.00045012502232566476 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00026879197685047984 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00020479195518419147 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00313895900035277 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0008001670357771218 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.0004587919684126973 + }, + { + "thread": "filter", + "sql_shape": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "seconds": 0.0008829580037854612 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`epoch_uuid`,`included`,`tags`,`review_state`,`revision`,`metadata_fingerprint` FROM `recording_workspace`.`curation` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))AND( ( (`epoch_uuid`='?') OR (", + "seconds": 0.001604916003998369 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`dataset_uuid`,`created_at`,`artifact_sha256` FROM `recording_workspace`.`dataset_revision` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0007313330424949527 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.005572959023993462 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.0006252499879337847 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.000411542016081512 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00019879097817465663 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00023737503215670586 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00033245899248868227 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0007911670254543424 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004128749715164304 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.0002832919708453119 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005226670182310045 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002677920274436474 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003719590022228658 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0004917919868603349 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00024750002194195986 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00031995802419260144 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00021849997574463487 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005769999697804451 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0014615000109188259 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0005247920053079724 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00029312499100342393 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005268339882604778 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00032354099676012993 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004479580093175173 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0004295419785194099 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00016670901095494628 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0002632910036481917 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.00046158296754583716 + } + ], + "limits": "Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap." + }, + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "2aa92db9-6472-4c39-9292-5794937593db", + "reused": true, + "phase": "complete", + "seconds": 0.068206 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "2aa92db9-6472-4c39-9292-5794937593db", + "reused": true, + "phase": "complete", + "seconds": 0.114146 + }, + "seconds": 0.1826643330277875, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "workflow_peak_rss_before_durable_oracle_bytes": 941637632, + "durable_snapshot_verify_seconds": 8.10934654099401, + "loaded_product_modules": { + "workspace_tree": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tree.py", + "workspace_predicates": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_predicates.py", + "workspace_cache_lifecycle": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_cache_lifecycle.py", + "workspace_metadata_objects": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_metadata_objects.py", + "workspace_disk_index": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py", + "workspace_catalog_identity": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_catalog_identity.py", + "recording_workspace": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/recording_workspace.py", + "workspace_recipes": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_recipes.py", + "workspace_tree_code": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tree_code.py", + "workspace_service": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py", + "workspace_tree_pages": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tree_pages.py", + "workspace_projects": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_projects.py", + "workspace_mysql_profile": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_mysql_profile.py", + "workspace_native_mysql": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_native_mysql.py", + "workspace_mysql_runtime": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_mysql_runtime.py", + "workspace_storage": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_storage.py", + "workspace_diff": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_diff.py", + "workspace_protocol_identity": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_protocol_identity.py", + "workspace_import_check": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_import_check.py", + "workspace_audit": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_audit.py", + "workspace_api": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_api.py", + "workspace_state_snapshot": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_snapshot.py", + "workspace_author_preferences": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_author_preferences.py", + "workspace_curation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_curation.py", + "workspace_annotations": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_annotations.py", + "workspace_shared_tag_index": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_shared_tag_index.py", + "workspace_paths": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_paths.py", + "workspace_desktop_paths": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_desktop_paths.py", + "workspace_startup_registry": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_startup_registry.py", + "workspace_explorer": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_explorer.py", + "workspace_datastores": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_datastores.py", + "workspace_suggestions": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_suggestions.py", + "workspace_tag_predicates": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tag_predicates.py", + "workspace_export_folder": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_export_folder.py", + "workspace_import_progress": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_import_progress.py", + "workspace_project_preferences": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_project_preferences.py", + "workspace_protocol_state": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_protocol_state.py", + "workspace_state_generation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_generation.py", + "workspace_project_servers": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_project_servers.py", + "workspace_launcher": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_launcher.py", + "workspace_app_routes": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_app_routes.py", + "workspace_folder_browser": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_folder_browser.py", + "workspace_h5_inbox": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_h5_inbox.py", + "workspace_tag_exchange": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tag_exchange.py", + "workspace_external_tags": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_external_tags.py", + "workspace_qc": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_qc.py", + "workspace_search": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_search.py", + "workspace_matlab_masks": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matlab_masks.py", + "workspace_matlab_routes": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matlab_routes.py", + "workspace_mask_refresh": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_mask_refresh.py", + "workspace_matching_epochs": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matching_epochs.py", + "workspace_candidate_exports": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_candidate_exports.py", + "workspace_backup_scheduler": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_backup_scheduler.py", + "workspace_recovery_store": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_recovery_store.py", + "workspace_recovery_generation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_recovery_generation.py", + "workspace_annotation_preparation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_annotation_preparation.py", + "workspace_native_tag_lookup": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_native_tag_lookup.py", + "workspace_lifecycle": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_lifecycle.py", + "workspace_native_tag_filter": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_native_tag_filter.py" + }, + "owned_native_runtime_stopped": true, + "source_inventory_after": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "98e5ddf9f5ea388f8697f2c5ea4e176aaf860450e78e2993c0f576ac164e11b5", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "eb16d29e4e6656db8d47f6812cfa2a44c882a8624701ad5b590e85acfacf1388", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7afc6c297770800fb90e148ffeb4ad3d5c24c8e84f5a788094f3246f59f97782", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6286df8eb8ea15f0c2c558a9a42c291167277cb5654ec4dd132ad739e96733b1", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "bac9888aef2eac472e3278902f9285ed5651b0164fa1a76a665ab881c6927ee4", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "9f198eb78c0ccc44dfdd4aebd44c0dd890482d6020b0164c5acce4955e46f5e6", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "35a10441d0ba59e43c59ad564879b2b73eccc29cd19a2558e3eaf8db1a9f5782", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "source_unchanged": false, + "harness_unchanged": true, + "seconds": 212.61365483299596, + "finished_at": "2026-09-30T15:06:27.252955+00:00", + "peak_rss_bytes": 941637632, + "passed": false +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-500.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-500.json new file mode 100644 index 0000000..f1bd2e1 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-500.json @@ -0,0 +1,3307 @@ +{ + "scope": "Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy.\n\nEvery project/database is disposable. Acquisition metadata is synthetic; actual\nMySQL, triggers, Flask routes, derived indexes and each version's save hooks\nare used. Native SQL commits are checked immediately; any background recovery\nmirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude\noracle work, and do not model browser concurrency/rendering. Sequential bundle\ntimes are sums of their separately measured requests. Profiles are separate.\n", + "epochs": 500, + "profiles": 3, + "tags_per_annotation": 5, + "protocols": 2, + "samples": 5, + "source_root": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI", + "source_inventory_before": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "98e5ddf9f5ea388f8697f2c5ea4e176aaf860450e78e2993c0f576ac164e11b5", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "4c586415a445d806ffe8d64d74f4d53d6d453be6fdcb2b4812da49f69a4525a2", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "22de09a82f03fb9f7b88252c004fa81f25885d7480e0d4d3ce0b7aa9570fd872", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7afc6c297770800fb90e148ffeb4ad3d5c24c8e84f5a788094f3246f59f97782", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6286df8eb8ea15f0c2c558a9a42c291167277cb5654ec4dd132ad739e96733b1", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "6587dcb57e94489175dad26bbbfaa9142170f7eb1b947fe7b3becf40707e11cf", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "9f198eb78c0ccc44dfdd4aebd44c0dd890482d6020b0164c5acce4955e46f5e6", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "a75c94ce4c2a5863fb2bf5d79c6abaf4304fb7aa90726d89d80a9e69114d5710", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "3f5ec51667618b9e0a215f6371dd22a9e1502afd54166da0efb9b677045d4216", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "35a10441d0ba59e43c59ad564879b2b73eccc29cd19a2558e3eaf8db1a9f5782", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "fixture_module": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py", + "harness_sha256": "a2b5e70861826936fdb4c9d6a5c76efd7645486ad5ce05e1482e3e6aab694fde", + "started_at": "2026-09-30T15:00:24.760152+00:00", + "release_ready": false, + "operations": { + "first10_revision_preflight": { + "samples_seconds": [ + 0.006811458966694772, + 0.00572104100137949, + 0.005855125025846064, + 0.005982916976790875, + 0.0059248749748803675 + ], + "p50_seconds": 0.0059248749748803675, + "p95_seconds": 0.006811458966694772, + "p99_seconds": 0.006811458966694772, + "maximum_seconds": 0.006811458966694772, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15362, + "Questions": 4 + }, + { + "Bytes_sent": 15362, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + } + ] + }, + "first10_save": { + "samples_seconds": [ + 0.0397009999724105, + 0.015526416013017297, + 0.015385875012725592, + 0.01620404195273295, + 0.014777208969462663 + ], + "p50_seconds": 0.015526416013017297, + "p95_seconds": 0.0397009999724105, + "p99_seconds": 0.0397009999724105, + "maximum_seconds": 0.0397009999724105, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 18598, + "Questions": 36 + }, + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12423, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + } + ] + }, + "second10_revision_preflight": { + "samples_seconds": [ + 0.005753292003646493, + 0.0059770410298369825, + 0.005863624974153936, + 0.005840791971422732, + 0.006592250021640211 + ], + "p50_seconds": 0.005863624974153936, + "p95_seconds": 0.006592250021640211, + "p99_seconds": 0.006592250021640211, + "maximum_seconds": 0.006592250021640211, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15380, + "Questions": 4 + }, + { + "Bytes_sent": 15380, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + } + ] + }, + "second10_save": { + "samples_seconds": [ + 0.015676334034651518, + 0.015652582980692387, + 0.014553832996170968, + 0.017022708023432642, + 0.01785816700430587 + ], + "p50_seconds": 0.015676334034651518, + "p95_seconds": 0.01785816700430587, + "p99_seconds": 0.01785816700430587, + "maximum_seconds": 0.01785816700430587, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12435, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + } + ] + }, + "filter20": { + "samples_seconds": [ + 0.03799974999856204, + 0.021650042035616934, + 0.0209364999900572, + 0.021898082981351763, + 0.022155124985147268 + ], + "p50_seconds": 0.021898082981351763, + "p95_seconds": 0.03799974999856204, + "p99_seconds": 0.03799974999856204, + "maximum_seconds": 0.03799974999856204, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 156835, + "Questions": 83 + }, + { + "Bytes_sent": 134733, + "Questions": 57 + }, + { + "Bytes_sent": 134734, + "Questions": 57 + }, + { + "Bytes_sent": 134734, + "Questions": 57 + }, + { + "Bytes_sent": 134734, + "Questions": 57 + } + ] + }, + "cell_save": { + "samples_seconds": [ + 0.007789916999172419, + 0.006697749951854348, + 0.007052166038192809, + 0.007307749998290092, + 0.007273291994351894 + ], + "p50_seconds": 0.007273291994351894, + "p95_seconds": 0.007789916999172419, + "p99_seconds": 0.007789916999172419, + "maximum_seconds": 0.007789916999172419, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4165, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + } + ] + }, + "filter_cell100": { + "samples_seconds": [ + 0.04186395899159834, + 0.03950862505007535, + 0.040653792035300285, + 0.039671292004641145, + 0.03873795800609514 + ], + "p50_seconds": 0.039671292004641145, + "p95_seconds": 0.04186395899159834, + "p99_seconds": 0.04186395899159834, + "maximum_seconds": 0.04186395899159834, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 168042, + "Questions": 57 + }, + { + "Bytes_sent": 168042, + "Questions": 57 + }, + { + "Bytes_sent": 168043, + "Questions": 57 + }, + { + "Bytes_sent": 168043, + "Questions": 57 + }, + { + "Bytes_sent": 168043, + "Questions": 57 + } + ] + }, + "filter_cell_and_epoch10": { + "samples_seconds": [ + 0.01839087496045977, + 0.018143708002753556, + 0.022742124972864985, + 0.01809895900078118, + 0.01865949999773875 + ], + "p50_seconds": 0.01839087496045977, + "p95_seconds": 0.022742124972864985, + "p99_seconds": 0.022742124972864985, + "maximum_seconds": 0.022742124972864985, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 125358, + "Questions": 58 + }, + { + "Bytes_sent": 125358, + "Questions": 58 + }, + { + "Bytes_sent": 125359, + "Questions": 58 + }, + { + "Bytes_sent": 125359, + "Questions": 58 + }, + { + "Bytes_sent": 125359, + "Questions": 58 + } + ] + }, + "remove_first10_revision_preflight": { + "samples_seconds": [ + 0.005876458017155528, + 0.005922999989707023, + 0.006230500002857298, + 0.0060287920059636235, + 0.006431999965570867 + ], + "p50_seconds": 0.0060287920059636235, + "p95_seconds": 0.006431999965570867, + "p99_seconds": 0.006431999965570867, + "maximum_seconds": 0.006431999965570867, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15799, + "Questions": 4 + }, + { + "Bytes_sent": 15799, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + } + ] + }, + "remove_first10_save": { + "samples_seconds": [ + 0.016493040951900184, + 0.0152747500105761, + 0.018004917015787214, + 0.015299541992135346, + 0.018318833026569337 + ], + "p50_seconds": 0.016493040951900184, + "p95_seconds": 0.018318833026569337, + "p99_seconds": 0.018318833026569337, + "maximum_seconds": 0.018318833026569337, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12423, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + } + ] + }, + "filter_hierarchy_after_epoch_remove": { + "samples_seconds": [ + 0.01246662496123463, + 0.01156399998581037, + 0.01460758299799636, + 0.012225457991007715, + 0.012653290992602706 + ], + "p50_seconds": 0.01246662496123463, + "p95_seconds": 0.01460758299799636, + "p99_seconds": 0.01460758299799636, + "maximum_seconds": 0.01460758299799636, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112890, + "Questions": 55 + }, + { + "Bytes_sent": 112890, + "Questions": 55 + }, + { + "Bytes_sent": 112891, + "Questions": 55 + }, + { + "Bytes_sent": 112891, + "Questions": 55 + }, + { + "Bytes_sent": 112891, + "Questions": 55 + } + ] + }, + "filter_remaining10": { + "samples_seconds": [ + 0.01550741697428748, + 0.017109708045609295, + 0.018612417043186724, + 0.017108583997469395, + 0.017651750007644296 + ], + "p50_seconds": 0.017109708045609295, + "p95_seconds": 0.018612417043186724, + "p99_seconds": 0.018612417043186724, + "maximum_seconds": 0.018612417043186724, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 124593, + "Questions": 57 + }, + { + "Bytes_sent": 124593, + "Questions": 57 + }, + { + "Bytes_sent": 124594, + "Questions": 57 + }, + { + "Bytes_sent": 124594, + "Questions": 57 + }, + { + "Bytes_sent": 124594, + "Questions": 57 + } + ] + }, + "remove_second10_revision_preflight": { + "samples_seconds": [ + 0.006006916984915733, + 0.006016999948769808, + 0.0059361670282669365, + 0.005967749981209636, + 0.00590987503528595 + ], + "p50_seconds": 0.005967749981209636, + "p95_seconds": 0.006016999948769808, + "p99_seconds": 0.006016999948769808, + "maximum_seconds": 0.006016999948769808, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + } + ] + }, + "remove_second10_save": { + "samples_seconds": [ + 0.015905459003988653, + 0.015918832970783114, + 0.01652000000467524, + 0.01596254203468561, + 0.015179125010035932 + ], + "p50_seconds": 0.015918832970783114, + "p95_seconds": 0.01652000000467524, + "p99_seconds": 0.01652000000467524, + "maximum_seconds": 0.01652000000467524, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12435, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + } + ] + }, + "filter_after_all_epoch_removals": { + "samples_seconds": [ + 0.011529624985996634, + 0.011944708006922156, + 0.01212529098847881, + 0.012091375014279038, + 0.012476667005103081 + ], + "p50_seconds": 0.012091375014279038, + "p95_seconds": 0.012476667005103081, + "p99_seconds": 0.012476667005103081, + "maximum_seconds": 0.012476667005103081, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + } + ] + }, + "remove_cell_save": { + "samples_seconds": [ + 0.007468916999641806, + 0.006469584011938423, + 0.007360292016528547, + 0.00706408399855718, + 0.007187874987721443 + ], + "p50_seconds": 0.007187874987721443, + "p95_seconds": 0.007468916999641806, + "p99_seconds": 0.007468916999641806, + "maximum_seconds": 0.007468916999641806, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4165, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + } + ] + }, + "filter_after_cell_removal": { + "samples_seconds": [ + 0.012379000021610409, + 0.013237042003311217, + 0.012182208010926843, + 0.011354041984304786, + 0.011573958967346698 + ], + "p50_seconds": 0.012182208010926843, + "p95_seconds": 0.013237042003311217, + "p99_seconds": 0.013237042003311217, + "maximum_seconds": 0.013237042003311217, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + } + ] + }, + "tag10_then10_filter20_http_total": { + "samples_seconds": [ + 0.10594183497596532, + 0.06452712306054309, + 0.06259495799895376, + 0.06694854190573096, + 0.06730762595543638 + ], + "p50_seconds": 0.06694854190573096, + "p95_seconds": 0.10594183497596532, + "p99_seconds": 0.10594183497596532, + "maximum_seconds": 0.10594183497596532, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "cell_tag_then_cell_filter_http_total": { + "samples_seconds": [ + 0.04965387599077076, + 0.0462063750019297, + 0.04770595807349309, + 0.04697904200293124, + 0.046011250000447035 + ], + "p50_seconds": 0.04697904200293124, + "p95_seconds": 0.04965387599077076, + "p99_seconds": 0.04965387599077076, + "maximum_seconds": 0.04965387599077076, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "first10_selected_action_http_total": { + "samples_seconds": [ + 0.04651245893910527, + 0.021247457014396787, + 0.021241000038571656, + 0.022186958929523826, + 0.02070208394434303 + ], + "p50_seconds": 0.021247457014396787, + "p95_seconds": 0.04651245893910527, + "p99_seconds": 0.04651245893910527, + "maximum_seconds": 0.04651245893910527, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "second10_selected_action_http_total": { + "samples_seconds": [ + 0.02142962603829801, + 0.02162962401052937, + 0.020417457970324904, + 0.022863499994855374, + 0.02445041702594608 + ], + "p50_seconds": 0.02162962401052937, + "p95_seconds": 0.02445041702594608, + "p99_seconds": 0.02445041702594608, + "maximum_seconds": 0.02445041702594608, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "autocomplete_cold_diagnostic": { + "samples_seconds": [ + 0.025664957996923476 + ], + "p50_seconds": 0.025664957996923476, + "p95_seconds": 0.025664957996923476, + "p99_seconds": 0.025664957996923476, + "maximum_seconds": 0.025664957996923476, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 214891, + "Questions": 89 + } + ] + }, + "autocomplete_warm_diagnostic": { + "samples_seconds": [ + 0.02846150001278147 + ], + "p50_seconds": 0.02846150001278147, + "p95_seconds": 0.02846150001278147, + "p99_seconds": 0.02846150001278147, + "maximum_seconds": 0.02846150001278147, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 214891, + "Questions": 89 + } + ] + }, + "same_server_native_reuse_filter20": { + "samples_seconds": [ + 0.019670958979986608 + ], + "p50_seconds": 0.019670958979986608, + "p95_seconds": 0.019670958979986608, + "p99_seconds": 0.019670958979986608, + "maximum_seconds": 0.019670958979986608, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 134735, + "Questions": 57 + } + ] + } + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 167 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "page_cells": true, + "target_specification": "tag10_then10_filter20_and_cell_epoch_hierarchy", + "baseline_harness_sha256": "272fe050c8762ed4ea45bd013e236e8723d8fe46f5e7e293c58e2edf1fd52ddc", + "mysql_version": "8.4.2", + "seed_seconds": 0.41018587502185255, + "seed_checkpoint_seconds": 0.17138437496032566, + "native_lookup_startup_preparation": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "7c07d8c5-6f30-473f-90be-19146e25d0c8", + "reused": false, + "phase": "complete", + "seconds": 0.165026 + }, + "selected_epoch_uuids": { + "first10": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5" + ], + "second10": [ + "ad573668-6512-6e55-649e-cb23ae1d4888", + "16dc368a-89b4-28b2-4854-84313ba67a39", + "37834f2f-2576-2f23-e1f7-4a531cbe445d", + "454f63ac-30c8-3229-97ef-025edff6abd2", + "5ef6fdf3-2513-aa7c-d11f-72beccf132b9", + "1253e937-3e78-1b75-0026-6caa55150e08", + "482d9673-cfee-5de3-91f9-7fde4d1c84f9", + "3346f2bb-f6c3-4bd2-dbe2-8bd1bb657d0e", + "9537f32e-c759-9e1a-e953-af6c9f929fe7", + "0fd42b3f-73c4-48b3-4940-b339f87d07ad" + ], + "cell": "0604cd31-38fe-ed20-2ef2-93e062da2f47", + "cell_children": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5", + "4a44dc15-3642-04a8-0fe8-0e9039455cc1", + "4fc82b26-aecb-47d2-868c-4efbe3581732", + "6b51d431-df5d-7f14-1cbe-ceccf79edf3d", + "3fdba35f-04dc-8c46-2986-c992bcf87554", + "8527a891-e224-1369-50ff-32ca212b45bc", + "e629fa65-98d7-3276-8f7c-726b4b621285", + "b17ef6d1-9c7a-5b1e-e83b-907c595526dc", + "4523540f-1504-cd17-100c-4835e85b7eef", + "4ec9599f-c203-d176-a301-536c2e091a19", + "9400f1b2-1cb5-27d7-fa3d-3eabba93557a", + "f5ca38f7-48a1-d6ea-f726-b8a42fb575c3", + "6f4b6612-125f-b3a0-daec-d2799dfd6c9c", + "785f3ec7-eb32-f30b-90cd-0fcf3657d388", + "535fa30d-7e25-dd8a-49f1-536779734ec8", + "c2356069-e9d1-e79c-a924-378153cfbbfb", + "b7a56873-cd77-1f2c-446d-369b649430b6", + "5f9c4ab0-8cac-7457-e911-1a30e4664920", + "670671cd-9740-4156-226e-507973f2ab83", + "59e19706-d51d-39f6-6711-c2653cd7eb12", + "35135aaa-6cc2-3891-b40c-b3f378c53a17", + "624b60c5-8c9d-8bfb-6ff1-886c2fd605d2", + "eb1e33e8-a81b-697b-7585-5af6bfcdbcbf", + "e29c9c18-0c62-79b0-b02a-bd6a1801c7c0", + "c6f3ac57-944a-5314-90cd-39902d0f7777", + "86e50149-6586-6131-2a9e-0b35558d84f6", + "9f14025a-f006-5b30-e47e-23ebb3b491d3", + "76a50887-d8f1-c2e9-3017-55428990ad81", + "7a61b537-01be-fdae-0eee-ffaecc73f14e", + "aea92132-c4cb-eb26-3e6a-c2bf6c183b5d", + "0b918943-df09-62bc-7a18-24c0555a3893", + "d59eced1-ded0-7f84-c145-592f65bdf854", + "3d914f93-48c9-cc0f-f8a7-9716700b9fcd", + "73475cb4-0a56-8e8d-a8a0-45ced110137e", + "44cb730c-4204-80a0-477b-505ae68af508", + "71ee45a3-c0db-9a98-65f7-313dd3372cf6", + "811786ad-1ae7-4adf-dd20-dd0372abaaeb", + "25fc0e70-96fc-6537-1820-2dc30b0c580b", + "31489056-e091-6d59-fe3a-dd79e63f095a", + "98010bd9-270f-9b10-0b62-14a21754fd33", + "0e17daca-5f3e-175f-448b-acace3bc0da4", + "1a656259-0ef1-9d10-45d0-6c4055742d38", + "031b4af5-197e-c30a-926f-48cf40e11a7d", + "41cfc0d1-f2d1-27b0-4555-b7246d84019b", + "2858dcd1-057d-3eae-7f7d-5f782167e24b", + "2fca346d-b656-1871-02ce-806ac732e06a", + "02d20bbd-7e39-4ad5-999a-4cebabac9619", + "7688b6ef-5255-5962-d008-fff894223582", + "c837649c-ce43-f272-9138-e72cc3152070", + "6208ef0f-7750-c111-548c-f90b6ea1d0d0", + "3e1e967e-9b79-3e90-8f8e-ae83c74dba9b", + "39fa9ec1-90ee-e7b6-f4df-f1100d6343e1", + "d029fa3a-95e1-74a1-9934-857f535eb942", + "81b8a03f-97e8-787c-53fe-1a86bda042b6", + "da4ea2a5-506f-2693-eae1-90d9360a1f31", + "a68b412c-4282-555f-1554-6cf6e1fc4289", + "108c995b-953c-8a35-5611-03e2014cf828", + "3ada92f2-8b4c-eda3-8562-ebf047c6ff05", + "49d180ec-f561-3281-9571-bf39d9b7b342", + "a21855da-08cb-102d-1d21-7c53dc5824a3", + "c75cb66a-e28d-8ebc-6ede-d002c28a8ba0", + "ff5a1ae0-12af-a5d4-c889-c50ad427aaf5", + "7f2253d7-e228-b22a-08bd-a1f09c516f6f", + "87226162-0421-7edd-b39e-7df969e0698a", + "96061e92-f58e-4bdc-dee7-3df36183fe3a", + "eb624dbe-56eb-6620-ae62-080c10a273ca", + "f369cb89-fc62-7e66-8987-007d121ed1ea", + "f74efabe-f12e-a619-e30b-79bddef89cff", + "a88a7902-cb4e-f697-ba0b-6759c50e8c10", + "349c4120-1b62-db85-1192-665c504b350f", + "98a3ab7c-340e-8a03-3e7b-37b6ef942875", + "48449a14-a4ff-7d79-bb7a-1b6f3d488eba", + "5316ca1c-5ddc-a8e6-cecc-fce58f3b8540", + "a46e3763-2fa6-ca51-a13f-e39a567b3c23", + "bbb965ab-0c80-d653-8cf2-184babad2a56", + "44c8031c-b036-a735-0d8b-9b8603af662a", + "b4944c6f-f08d-c6f4-3da2-e9c824669b7d", + "434c9b5a-e514-646b-bd91-b50032ca579e", + "bdd2d3af-3a5a-1213-497d-4f1f7bfcda89", + "8b940be7-fb78-aaa6-b656-7dd7a3987996", + "cd70bea0-23f7-52a0-564a-bb6ed08d42c1", + "69f59c27-3b6e-669a-c32a-6dd5e1b2cb63", + "1da51b8d-8ff9-8f6a-48f8-0ae79fe3ca6c", + "82416496-09f8-8ccd-2a0a-5b233a07a538", + "6e400187-1c0c-f27c-7634-ef1dc478408f", + "e3d6c4d4-599e-0088-2384-ca981ee287ed", + "ad48ff99-415b-2f00-7dc3-5b7eb553fd1e", + "7b1a278f-5abe-8e9d-a907-fc9c29dfd432", + "d6d824ab-ba4a-fde8-1129-c71dea75b810", + "29db0c67-82db-d500-0559-ef4d9e953e30", + "8c1f1046-219d-dd21-6a02-3f792356ddf1" + ] + }, + "backup_receipts": [ + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 1, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 2, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 3, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 4, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 5, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 6, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 7, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 8, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 9, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 10, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 11, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 12, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 13, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 14, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 15, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 16, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 17, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 18, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 19, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 20, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 21, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 22, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 23, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 24, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 25, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 26, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 27, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 28, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 29, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 30, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_first10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:00:32.685142+00:00", + "pending": true, + "requested_sequence": 31, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_second10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:00:32.685142+00:00", + "pending": true, + "requested_sequence": 32, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_first10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:00:32.948785+00:00", + "pending": true, + "requested_sequence": 33, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_second10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:00:32.948785+00:00", + "pending": true, + "requested_sequence": 34, + "running": false, + "status": "pending" + }, + "database": "committed" + } + } + ], + "preparation_index_seconds": 0, + "lookup_mode": "persistent_native_sql_no_post_seed_tag_cache_preparation", + "bundle_definitions": { + "tag10_then10_filter20_http_total": [ + "first10_revision_preflight", + "first10_save", + "second10_revision_preflight", + "second10_save", + "filter20" + ], + "cell_tag_then_cell_filter_http_total": [ + "cell_save", + "filter_cell100" + ], + "first10_selected_action_http_total": [ + "first10_revision_preflight", + "first10_save" + ], + "second10_selected_action_http_total": [ + "second10_revision_preflight", + "second10_save" + ] + }, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:00:33.647722+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 0.006383416010066867 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 0.0028258750098757446 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 0.007205624948255718 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 0.0027852500206790864 + } + ] + }, + "autocomplete_query_plans": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY,by_tag", + "key": "PRIMARY", + "key_len": "38", + "ref": "const", + "rows": 3787, + "filtered": 100.0, + "Extra": "Using index; Using filesort" + } + ] + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "explain": [ + { + "id": 1, + "select_type": "PRIMARY", + "table": "", + "partitions": null, + "type": "ALL", + "possible_keys": null, + "key": null, + "key_len": null, + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": null + }, + { + "id": 1, + "select_type": "PRIMARY", + "table": "a", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "111", + "ref": "const,func", + "rows": 1, + "filtered": 5.0, + "Extra": "Using where" + }, + { + "id": 2, + "select_type": "DERIVED", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY,by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "filter20_cpu_profile": { + "top_functions": [ + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 313, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.541e-06, + "cumulative_seconds": 0.054274083 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 159, + "function": "request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.79e-06, + "cumulative_seconds": 0.054249583000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1163, + "function": "get", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.459000000000001e-06, + "cumulative_seconds": 0.053411834000000005 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/testing.py", + "line": 204, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.2751e-05, + "cumulative_seconds": 0.053406375000000006 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1062, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.2500000000000006e-06, + "cumulative_seconds": 0.053143458000000005 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 984, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.958e-06, + "cumulative_seconds": 0.05312962500000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1230, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.8780000000000006e-06, + "cumulative_seconds": 0.052947917000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1529, + "function": "__call__", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.500000000000001e-06, + "cumulative_seconds": 0.052924375 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1479, + "function": "wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0209e-05, + "cumulative_seconds": 0.052918875000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 904, + "function": "full_dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 7.624e-06, + "cumulative_seconds": 0.052687500000000005 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 879, + "function": "dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 7.2209e-05, + "cumulative_seconds": 0.052494375 + }, + { + "file": "python/workspace_api.py", + "line": 716, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 7.2328e-05, + "cumulative_seconds": 0.05241875 + }, + { + "file": "python/workspace_annotations.py", + "line": 295, + "function": "for_epochs", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.590400000000001e-05, + "cumulative_seconds": 0.021142541 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 304, + "function": "traced_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000196102, + "cumulative_seconds": 0.020249043 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 412, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 9.642e-05, + "cumulative_seconds": 0.019690752000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 402, + "function": "_execute_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00010849500000000001, + "cumulative_seconds": 0.019441834 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 27, + "calls": 38, + "self_seconds": 2.7003000000000002e-05, + "cumulative_seconds": 0.019405418 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 249, + "function": "native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.0292e-05, + "cumulative_seconds": 0.019342208 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 150, + "function": "execute", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.5366000000000005e-05, + "cumulative_seconds": 0.019082372 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 332, + "function": "_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.423400000000001e-05, + "cumulative_seconds": 0.018632707000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 575, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.283100000000001e-05, + "cumulative_seconds": 0.018174499 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 851, + "function": "_read_query_result", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.4294000000000006e-05, + "cumulative_seconds": 0.017274794 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1288, + "function": "read", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.753400000000001e-05, + "cumulative_seconds": 0.017198458 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 128, + "function": "deepcopy", + "primitive_calls": 78, + "calls": 17170, + "self_seconds": 0.00932983, + "cumulative_seconds": 0.015814497 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 201, + "function": "_deepcopy_list", + "primitive_calls": 62, + "calls": 102, + "self_seconds": 0.000296734, + "cumulative_seconds": 0.015689001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 101, + "function": "_rows", + "primitive_calls": 46, + "calls": 46, + "self_seconds": 5.2170000000000004e-05, + "cumulative_seconds": 0.015632377 + }, + { + "file": "python/workspace_state_generation.py", + "line": 197, + "function": "response_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.5e-05, + "cumulative_seconds": 0.015488125 + }, + { + "file": "python/workspace_state_generation.py", + "line": 233, + "function": "_attest_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 5.4624000000000004e-05, + "cumulative_seconds": 0.015459541 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 227, + "function": "_deepcopy_dict", + "primitive_calls": 1242, + "calls": 1284, + "self_seconds": 0.0027896590000000003, + "cumulative_seconds": 0.013735265000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 763, + "function": "_read_packet", + "primitive_calls": 765, + "calls": 765, + "self_seconds": 0.0011524550000000001, + "cumulative_seconds": 0.012796017000000002 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 813, + "function": "_read_bytes", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.000545364, + "cumulative_seconds": 0.009765910000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 141, + "function": "__exit__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 3.5430000000000002e-06, + "cumulative_seconds": 0.00970025 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 132, + "function": "__enter__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 2.5410000000000003e-06, + "cumulative_seconds": 0.009647083 + }, + { + "file": "python/workspace_state_generation.py", + "line": 134, + "function": "_active_ddl_guard", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 3.2710000000000004e-05, + "cumulative_seconds": 0.009180917 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.000207604, + "cumulative_seconds": 0.009142557 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/socket.py", + "line": 704, + "function": "readinto", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 6.491400000000001e-05, + "cumulative_seconds": 0.008934953 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1299, + "function": "recv_into", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 7.657700000000001e-05, + "cumulative_seconds": 0.008833749 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1157, + "function": "read", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 4.5587e-05, + "cumulative_seconds": 0.008747209 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 0.008697289, + "cumulative_seconds": 0.008697289 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1370, + "function": "_read_result_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.8163000000000005e-05, + "cumulative_seconds": 0.007926465 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/__init__.py", + "line": 138, + "function": "jsonify", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.6240000000000004e-06, + "cumulative_seconds": 0.007166041000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 189, + "function": "response", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.0916e-05, + "cumulative_seconds": 0.007155000000000001 + }, + { + "file": "python/workspace_api.py", + "line": 61, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.6960000000000005e-05, + "cumulative_seconds": 0.007076917 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 869, + "function": "to_dicts", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 1.8752000000000003e-05, + "cumulative_seconds": 0.006889543000000001 + }, + { + "file": "python/workspace_api.py", + "line": 62, + "function": "browser_safe", + "primitive_calls": 1, + "calls": 9641, + "self_seconds": 0.003157097, + "cumulative_seconds": 0.0056334160000000005 + }, + { + "file": "python/workspace_api.py", + "line": 66, + "function": "", + "primitive_calls": 1, + "calls": 1363, + "self_seconds": 0.001445494, + "cumulative_seconds": 0.005631625 + }, + { + "file": "python/workspace_api.py", + "line": 68, + "function": "", + "primitive_calls": 2, + "calls": 102, + "self_seconds": 0.000189636, + "cumulative_seconds": 0.005620333 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1416, + "function": "_read_rowdata_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000339208, + "cumulative_seconds": 0.005085877 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 1231, + "function": "cursor", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 1.4335e-05, + "cumulative_seconds": 0.00477875 + }, + { + "file": "python/workspace_annotations.py", + "line": 173, + "function": "_rows", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 9.921e-06, + "cumulative_seconds": 0.004233417000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 268, + "function": "_native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.8083000000000002e-05, + "cumulative_seconds": 0.003803166 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 311, + "function": "native_context", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.0876e-05, + "cumulative_seconds": 0.0037510420000000004 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1429, + "function": "_read_row_from_packet", + "primitive_calls": 428, + "calls": 428, + "self_seconds": 0.000901201, + "cumulative_seconds": 0.0030138200000000004 + }, + { + "file": "python/workspace_state_generation.py", + "line": 125, + "function": "_observer_status", + "primitive_calls": 8, + "calls": 8, + "self_seconds": 2.6455e-05, + "cumulative_seconds": 0.002907666 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1448, + "function": "_get_descriptions", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00030576800000000004, + "cumulative_seconds": 0.0027617970000000003 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 163, + "function": "read_length_coded_string", + "primitive_calls": 2712, + "calls": 2712, + "self_seconds": 0.000823981, + "cumulative_seconds": 0.0024374170000000003 + }, + { + "file": "python/workspace_state_generation.py", + "line": 115, + "function": "_triggers", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 9.59e-07, + "cumulative_seconds": 0.002420209 + }, + { + "file": "python/workspace_state_generation.py", + "line": 107, + "function": "_ddl", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 2.6868e-05, + "cumulative_seconds": 0.002107042 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 898, + "function": "", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 5.0951e-05, + "cumulative_seconds": 0.002088458 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 185, + "function": "_metadata", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.8792000000000002e-05, + "cumulative_seconds": 0.00182825 + }, + { + "file": "python/workspace_annotations.py", + "line": 195, + "function": "_chips", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 3.8617e-05, + "cumulative_seconds": 0.00182292 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 899, + "function": "", + "primitive_calls": 86, + "calls": 86, + "self_seconds": 0.00034619500000000004, + "cumulative_seconds": 0.0017873770000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 101, + "function": "selected", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.121000000000001e-06, + "cumulative_seconds": 0.001738416 + }, + { + "file": "python/workspace_annotations.py", + "line": 188, + "function": "_validated_tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 5.9242000000000006e-05, + "cumulative_seconds": 0.0016865060000000002 + }, + { + "file": "python/workspace_curation.py", + "line": 170, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.332e-06, + "cumulative_seconds": 0.00164575 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 183, + "function": "dumps", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.1914e-05, + "cumulative_seconds": 0.001609041 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 183, + "function": "encode", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 1.8209e-05, + "cumulative_seconds": 0.0015800430000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 205, + "function": "iterencode", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 0.001558708, + "cumulative_seconds": 0.001558708 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 232, + "function": "__init__", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 8.5381e-05, + "cumulative_seconds": 0.0015486360000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 37540, + "calls": 37540, + "self_seconds": 0.00153531, + "cumulative_seconds": 0.00153531 + }, + { + "file": "python/workspace_service.py", + "line": 748, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.1166e-05, + "cumulative_seconds": 0.001464709 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 236, + "function": "_parse_field_descriptor", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 0.000335937, + "cumulative_seconds": 0.00144242 + }, + { + "file": "python/workspace_service.py", + "line": 778, + "function": "_epoch_page_identities", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.5844e-05, + "cumulative_seconds": 0.0014215 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 166, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.125e-06, + "cumulative_seconds": 0.001406541 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 282, + "function": "__and__", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 1.0668e-05, + "cumulative_seconds": 0.001164167 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 178, + "function": "restrict", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 7.737400000000001e-05, + "cumulative_seconds": 0.001153499 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 223, + "function": "attributes", + "primitive_calls": 1006, + "calls": 1006, + "self_seconds": 0.000372064, + "cumulative_seconds": 0.001152573 + }, + { + "file": "python/workspace_annotations.py", + "line": 34, + "function": "text", + "primitive_calls": 416, + "calls": 416, + "self_seconds": 0.00034434200000000003, + "cumulative_seconds": 0.0011120140000000001 + }, + { + "file": "python/workspace_explorer.py", + "line": 60, + "function": "protocol_binding_header", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 1.2746000000000001e-05, + "cumulative_seconds": 0.00109525 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 299, + "function": "loads", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 5.6668e-05, + "cumulative_seconds": 0.001059706 + }, + { + "file": "python/workspace_state_generation.py", + "line": 347, + "function": "token", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 1.0581e-05, + "cumulative_seconds": 0.0010067070000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 61, + "function": "read", + "primitive_calls": 2712, + "calls": 2712, + "self_seconds": 0.000882678, + "cumulative_seconds": 0.000998633 + }, + { + "file": "python/workspace_annotations.py", + "line": 40, + "function": "tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.6506e-05, + "cumulative_seconds": 0.00099105 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 22, + "calls": 78, + "self_seconds": 5.3205e-05, + "cumulative_seconds": 0.0009847080000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 359, + "function": "_fresh_token", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.4166000000000001e-05, + "cumulative_seconds": 0.000982375 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 285, + "function": "__getitem__", + "primitive_calls": 745, + "calls": 745, + "self_seconds": 0.00014096100000000002, + "cumulative_seconds": 0.0009730740000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/decoder.py", + "line": 332, + "function": "decode", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 8.482300000000001e-05, + "cumulative_seconds": 0.0009629560000000001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 311, + "function": "_scope", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 9.795e-06, + "cumulative_seconds": 0.0009457930000000001 + }, + { + "file": "python/workspace_service.py", + "line": 236, + "function": "source_scope", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.8468000000000003e-05, + "cumulative_seconds": 0.0009385830000000001 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 20369, + "calls": 20369, + "self_seconds": 0.0009083400000000001, + "cumulative_seconds": 0.000934426 + }, + { + "file": "python/workspace_annotations.py", + "line": 42, + "function": "", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 5.7363000000000006e-05, + "cumulative_seconds": 0.0009112090000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 261, + "function": "filter_epoch_ids", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.372e-05, + "cumulative_seconds": 0.000866833 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/datajoint/condition.py", + "line": 278, + "function": "make_condition", + "primitive_calls": 14, + "calls": 56, + "self_seconds": 0.00023307000000000002, + "cumulative_seconds": 0.000858958 + }, + { + "file": "python/workspace_datastores.py", + "line": 192, + "function": "source_states", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 6.79e-06, + "cumulative_seconds": 0.000854916 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/wrappers/response.py", + "line": 601, + "function": "get_json", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.1260000000000002e-06, + "cumulative_seconds": 0.0008338340000000001 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 456, + "calls": 456, + "self_seconds": 0.00023371400000000002, + "cumulative_seconds": 0.000833748 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/decoder.py", + "line": 343, + "function": "raw_decode", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 0.000832791, + "cumulative_seconds": 0.000832791 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 181, + "function": "loads", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.5e-06, + "cumulative_seconds": 0.0008173330000000001 + }, + { + "file": ".rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 869, + "function": "_execute_command", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00016949400000000001, + "cumulative_seconds": 0.000815087 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 207, + "function": "_metadata_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.8793e-05, + "cumulative_seconds": 0.000744291 + } + ], + "native_sql_calls": [ + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.000690957996994257 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00035266700433567166 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00018516700947657228 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00040933297714218497 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00020754203433170915 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00032491603633388877 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0003042080206796527 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00013237498933449388 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0002060839906334877 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00017895898781716824 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00044425000669434667 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0012032919912599027 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00032829202245920897 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00018783402629196644 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00037687504664063454 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00020004104590043426 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003575420123524964 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0003186250105500221 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00014462496619671583 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0002282499917782843 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.00041574996430426836 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0002098330296576023 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.000166917045135051 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00022633298067376018 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00029020803049206734 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.000230583013035357 + }, + { + "thread": "filter", + "sql_shape": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "seconds": 0.00038166699232533574 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`epoch_uuid`,`included`,`tags`,`review_state`,`revision`,`metadata_fingerprint` FROM `recording_workspace`.`curation` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))AND( ( (`epoch_uuid`='?') OR (", + "seconds": 0.0007193329511210322 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`dataset_uuid`,`created_at`,`artifact_sha256` FROM `recording_workspace`.`dataset_revision` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00022025004727765918 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.0015987499500624835 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.00046212499728426337 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0003293330082669854 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00019670795882120728 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00023145898012444377 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00031979201594367623 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0005031659966334701 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.000378583965357393 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00025212502805516124 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004041249630972743 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002279590116813779 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003369160112924874 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00033887499012053013 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00016108399722725153 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00022545800311490893 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00018754199845716357 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004633330390788615 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0012080839951522648 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003772909985855222 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00026299996534362435 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0003891250235028565 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00023641600273549557 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003325419966131449 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0002959170378744602 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00014779198681935668 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00024716596817597747 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003652920131571591 + } + ], + "limits": "Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap." + }, + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "7c07d8c5-6f30-473f-90be-19146e25d0c8", + "reused": true, + "phase": "complete", + "seconds": 0.064545 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "7c07d8c5-6f30-473f-90be-19146e25d0c8", + "reused": true, + "phase": "complete", + "seconds": 0.095174 + }, + "seconds": 0.1597440000041388, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "workflow_peak_rss_before_durable_oracle_bytes": 168656896, + "durable_snapshot_verify_seconds": 0.031988709000870585, + "loaded_product_modules": { + "workspace_tree": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tree.py", + "workspace_predicates": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_predicates.py", + "workspace_cache_lifecycle": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_cache_lifecycle.py", + "workspace_metadata_objects": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_metadata_objects.py", + "workspace_disk_index": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_disk_index.py", + "workspace_catalog_identity": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_catalog_identity.py", + "recording_workspace": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/recording_workspace.py", + "workspace_recipes": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_recipes.py", + "workspace_tree_code": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tree_code.py", + "workspace_service": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_service.py", + "workspace_tree_pages": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tree_pages.py", + "workspace_projects": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_projects.py", + "workspace_mysql_profile": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_mysql_profile.py", + "workspace_native_mysql": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_native_mysql.py", + "workspace_mysql_runtime": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_mysql_runtime.py", + "workspace_storage": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_storage.py", + "workspace_diff": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_diff.py", + "workspace_protocol_identity": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_protocol_identity.py", + "workspace_import_check": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_import_check.py", + "workspace_audit": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_audit.py", + "workspace_api": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_api.py", + "workspace_state_snapshot": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_snapshot.py", + "workspace_author_preferences": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_author_preferences.py", + "workspace_curation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_curation.py", + "workspace_annotations": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_annotations.py", + "workspace_shared_tag_index": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_shared_tag_index.py", + "workspace_paths": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_paths.py", + "workspace_desktop_paths": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_desktop_paths.py", + "workspace_startup_registry": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_startup_registry.py", + "workspace_explorer": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_explorer.py", + "workspace_datastores": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_datastores.py", + "workspace_suggestions": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_suggestions.py", + "workspace_tag_predicates": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tag_predicates.py", + "workspace_export_folder": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_export_folder.py", + "workspace_import_progress": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_import_progress.py", + "workspace_project_preferences": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_project_preferences.py", + "workspace_protocol_state": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_protocol_state.py", + "workspace_state_generation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_state_generation.py", + "workspace_project_servers": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_project_servers.py", + "workspace_launcher": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_launcher.py", + "workspace_app_routes": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_app_routes.py", + "workspace_folder_browser": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_folder_browser.py", + "workspace_h5_inbox": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_h5_inbox.py", + "workspace_tag_exchange": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_tag_exchange.py", + "workspace_external_tags": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_external_tags.py", + "workspace_qc": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_qc.py", + "workspace_search": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_search.py", + "workspace_matlab_masks": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matlab_masks.py", + "workspace_matlab_routes": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matlab_routes.py", + "workspace_mask_refresh": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_mask_refresh.py", + "workspace_matching_epochs": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_matching_epochs.py", + "workspace_candidate_exports": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_candidate_exports.py", + "workspace_backup_scheduler": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_backup_scheduler.py", + "workspace_recovery_store": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_recovery_store.py", + "workspace_recovery_generation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_recovery_generation.py", + "workspace_annotation_preparation": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_annotation_preparation.py", + "workspace_native_tag_lookup": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_native_tag_lookup.py", + "workspace_lifecycle": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_lifecycle.py", + "workspace_native_tag_filter": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/python/workspace_native_tag_filter.py" + }, + "owned_native_runtime_stopped": true, + "source_inventory_after": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "98e5ddf9f5ea388f8697f2c5ea4e176aaf860450e78e2993c0f576ac164e11b5", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "4c586415a445d806ffe8d64d74f4d53d6d453be6fdcb2b4812da49f69a4525a2", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "22de09a82f03fb9f7b88252c004fa81f25885d7480e0d4d3ce0b7aa9570fd872", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7afc6c297770800fb90e148ffeb4ad3d5c24c8e84f5a788094f3246f59f97782", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6286df8eb8ea15f0c2c558a9a42c291167277cb5654ec4dd132ad739e96733b1", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "6587dcb57e94489175dad26bbbfaa9142170f7eb1b947fe7b3becf40707e11cf", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "9f198eb78c0ccc44dfdd4aebd44c0dd890482d6020b0164c5acce4955e46f5e6", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "a75c94ce4c2a5863fb2bf5d79c6abaf4304fb7aa90726d89d80a9e69114d5710", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "3f5ec51667618b9e0a215f6371dd22a9e1502afd54166da0efb9b677045d4216", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "35a10441d0ba59e43c59ad564879b2b73eccc29cd19a2558e3eaf8db1a9f5782", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "source_unchanged": true, + "harness_unchanged": true, + "seconds": 9.550093834055588, + "finished_at": "2026-09-30T15:00:34.310755+00:00", + "peak_rss_bytes": 168656896, + "passed": true +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-results.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-results.json new file mode 100644 index 0000000..f770404 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-results.json @@ -0,0 +1,632 @@ +{ + "scope": "Native SQL lookup versus prior SQLite membership/vocabulary cache, same scientist tag workflow; isolated synthetic fixture; HTTP test client timings, not browser paint.", + "passed": false, + "workflow_correctness_checks_passed": true, + "source_and_harness_unchanged_across_both_native_runs": false, + "samples_per_workflow_operation": 5, + "source_inventory_sha256": "40bc48eab49a28794aae0e50858e5476c2332325720798e9ffc3f128b6994c25", + "native_harness_sha256": "a2b5e70861826936fdb4c9d6a5c76efd7645486ad5ce05e1482e3e6aab694fde", + "scales": { + "500": { + "native_receipt": "native-tag-sequence-pre-autocompletefix-500.json", + "receipt_passed": true, + "source_unchanged": true, + "changed_during_run": {}, + "prior_receipt": "tag-sequence-after-500.json", + "comparison_ms": { + "first10_save": { + "prior_p50": 15.186292002908885, + "native_p50": 15.526416013017297, + "native_first_sample": 39.7009999724105, + "native_maximum": 39.7009999724105 + }, + "second10_save": { + "prior_p50": 13.435167027637362, + "native_p50": 15.676334034651518, + "native_first_sample": 15.676334034651518, + "native_maximum": 17.85816700430587 + }, + "filter20": { + "prior_p50": 31.089458032511175, + "native_p50": 21.898082981351763, + "native_first_sample": 37.99974999856204, + "native_maximum": 37.99974999856204 + }, + "tag10_then10_filter20_http_total": { + "prior_p50": 73.59912293031812, + "native_p50": 66.94854190573096, + "native_first_sample": 105.94183497596532, + "native_maximum": 105.94183497596532 + }, + "cell_save": { + "prior_p50": 6.7298339563421905, + "native_p50": 7.273291994351894, + "native_first_sample": 7.789916999172419, + "native_maximum": 7.789916999172419 + }, + "filter_cell100": { + "prior_p50": 41.47870797896758, + "native_p50": 39.671292004641145, + "native_first_sample": 41.86395899159834, + "native_maximum": 41.86395899159834 + }, + "filter_cell_and_epoch10": { + "prior_p50": 17.395791015587747, + "native_p50": 18.39087496045977, + "native_first_sample": 18.39087496045977, + "native_maximum": 22.742124972864985 + }, + "cell_tag_then_cell_filter_http_total": { + "prior_p50": 48.06662496412173, + "native_p50": 46.97904200293124, + "native_first_sample": 49.65387599077076, + "native_maximum": 49.65387599077076 + } + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 167 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "autocomplete_query_plans": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY,by_tag", + "key": "PRIMARY", + "key_len": "38", + "ref": "const", + "rows": 3787, + "filtered": 100.0, + "Extra": "Using index; Using filesort" + } + ] + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "explain": [ + { + "id": 1, + "select_type": "PRIMARY", + "table": "", + "partitions": null, + "type": "ALL", + "possible_keys": null, + "key": null, + "key_len": null, + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": null + }, + { + "id": 1, + "select_type": "PRIMARY", + "table": "a", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "111", + "ref": "const,func", + "rows": 1, + "filtered": 5.0, + "Extra": "Using where" + }, + { + "id": 2, + "select_type": "DERIVED", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY,by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 0.006383416010066867 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 0.0028258750098757446 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 0.007205624948255718 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 0.0027852500206790864 + } + ] + }, + "autocomplete_diagnostic_ms": { + "autocomplete_cold_diagnostic": 25.664957996923476, + "autocomplete_warm_diagnostic": 28.46150001278147 + }, + "initial_empty_native_setup": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "7c07d8c5-6f30-473f-90be-19146e25d0c8", + "reused": false, + "phase": "complete", + "seconds": 0.165026 + }, + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "7c07d8c5-6f30-473f-90be-19146e25d0c8", + "reused": true, + "phase": "complete", + "seconds": 0.064545 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "7c07d8c5-6f30-473f-90be-19146e25d0c8", + "reused": true, + "phase": "complete", + "seconds": 0.095174 + }, + "seconds": 0.1597440000041388, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "same_server_native_reuse_filter_ms": 19.670958979986608, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:00:33.647722+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "mysql_version": "8.4.2", + "runtime_seconds": 9.550093834055588, + "seed_seconds": 0.41018587502185255, + "seed_checkpoint_seconds": 0.17138437496032566, + "owned_native_runtime_stopped": true + }, + "100000": { + "native_receipt": "native-tag-sequence-pre-autocompletefix-100000.json", + "receipt_passed": false, + "source_unchanged": false, + "changed_during_run": { + "python/tests/test_workspace_path_api.py": { + "before": "4c586415a445d806ffe8d64d74f4d53d6d453be6fdcb2b4812da49f69a4525a2", + "after": "eb16d29e4e6656db8d47f6812cfa2a44c882a8624701ad5b590e85acfacf1388" + }, + "python/workspace_api.py": { + "before": "6587dcb57e94489175dad26bbbfaa9142170f7eb1b947fe7b3becf40707e11cf", + "after": "bac9888aef2eac472e3278902f9285ed5651b0164fa1a76a665ab881c6927ee4" + }, + "python/workspace_paths.py": { + "before": "a75c94ce4c2a5863fb2bf5d79c6abaf4304fb7aa90726d89d80a9e69114d5710", + "after": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab" + }, + "python/workspace_projects.py": { + "before": "3f5ec51667618b9e0a215f6371dd22a9e1502afd54166da0efb9b677045d4216", + "after": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce" + } + }, + "prior_receipt": "tag-sequence-after-100000.json", + "comparison_ms": { + "first10_save": { + "prior_p50": 17.622290994040668, + "native_p50": 20.763959037140012, + "native_first_sample": 44.37404201598838, + "native_maximum": 44.37404201598838 + }, + "second10_save": { + "prior_p50": 16.18437498109415, + "native_p50": 24.33695795480162, + "native_first_sample": 27.478916046675295, + "native_maximum": 27.478916046675295 + }, + "filter20": { + "prior_p50": 119.21920796157792, + "native_p50": 124.48295799549669, + "native_first_sample": 984.3111250083894, + "native_maximum": 984.3111250083894 + }, + "tag10_then10_filter20_http_total": { + "prior_p50": 165.9542090492323, + "native_p50": 217.5220000790432, + "native_first_sample": 1074.6557911043055, + "native_maximum": 1074.6557911043055 + }, + "cell_save": { + "prior_p50": 7.809958013240248, + "native_p50": 8.591292018536478, + "native_first_sample": 8.944916015025228, + "native_maximum": 8.944916015025228 + }, + "filter_cell100": { + "prior_p50": 129.82887495309114, + "native_p50": 156.82324999943376, + "native_first_sample": 156.82324999943376, + "native_maximum": 162.14675002265722 + }, + "filter_cell_and_epoch10": { + "prior_p50": 106.19708400918171, + "native_p50": 124.58279100246727, + "native_first_sample": 116.38466699514538, + "native_maximum": 130.77333301771432 + }, + "cell_tag_then_cell_filter_http_total": { + "prior_p50": 137.83216592855752, + "native_p50": 165.76816601445898, + "native_first_sample": 165.76816601445898, + "native_maximum": 171.01029201876372 + } + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 33334 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 66666 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 66667 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "autocomplete_query_plans": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY,by_tag", + "key": "PRIMARY", + "key_len": "38", + "ref": "const", + "rows": 613093, + "filtered": 100.0, + "Extra": "Using index; Using filesort" + } + ] + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "explain": [ + { + "id": 1, + "select_type": "PRIMARY", + "table": "", + "partitions": null, + "type": "ALL", + "possible_keys": null, + "key": null, + "key_len": null, + "ref": null, + "rows": 183927, + "filtered": 100.0, + "Extra": null + }, + { + "id": 1, + "select_type": "PRIMARY", + "table": "a", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "111", + "ref": "const,func", + "rows": 1, + "filtered": 5.0, + "Extra": "Using where" + }, + { + "id": 2, + "select_type": "DERIVED", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "PRIMARY,by_tag", + "key": "PRIMARY", + "key_len": "38", + "ref": "const", + "rows": 613093, + "filtered": 30.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 5.976898541965056 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 4.200603792036418 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s GROUP BY tag", + "seconds": 5.332792375003919 + }, + { + "sql": "SELECT picked.tag,a.profile_uuid,a.author_name FROM (SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY tag,profile_uuid) picked JOIN `recording_workspace`.`shared_annotation` a ON a.project_uuid=%s AND a.profile_uuid=picked.profile_uuid AND a.target_kind=SUBSTRING_INDEX(picked.position,'/',1) AND a.target_uuid=SUBSTRING_INDEX(picked.position,'/',-1)", + "seconds": 4.116656041005626 + } + ] + }, + "autocomplete_diagnostic_ms": { + "autocomplete_cold_diagnostic": 10202.606874983758, + "autocomplete_warm_diagnostic": 9474.194333015475 + }, + "initial_empty_native_setup": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "2aa92db9-6472-4c39-9292-5794937593db", + "reused": false, + "phase": "complete", + "seconds": 0.173335 + }, + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "2aa92db9-6472-4c39-9292-5794937593db", + "reused": true, + "phase": "complete", + "seconds": 0.068206 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": {}, + "project_uuid": "2aa92db9-6472-4c39-9292-5794937593db", + "reused": true, + "phase": "complete", + "seconds": 0.114146 + }, + "seconds": 0.1826643330277875, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "same_server_native_reuse_filter_ms": 143.8881250214763, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:06:18.387002+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "mysql_version": "8.4.2", + "runtime_seconds": 212.61365483299596, + "seed_seconds": 115.08456225000555, + "seed_checkpoint_seconds": 14.813979834027123, + "owned_native_runtime_stopped": true + } + } +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-results.md b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-results.md new file mode 100644 index 0000000..1874396 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-autocompletefix-results.md @@ -0,0 +1,51 @@ +# Native SQL tag workflow validation + +The 500-epoch native SQL run passes. At 100,000 epochs all workflow correctness checks pass, but the overall receipt is invalidated by source changes during execution; its timings are provisional. The 100k run also exposes slow autocomplete (9–10 seconds), so these results do not support declaring the performance work complete. Neither run calls the legacy SQLite tag membership or refresh path. + +Each fixture has three profiles, five seeded tags per annotation, cell annotations, and two independent protocol curation scopes. The timed sequence reads revisions and durably tags 10 epochs, reads revisions and tags another 10 in another cell, then immediately filters the exact 20. Five complete cycles were measured. + +| Operation (median milliseconds) | 500 prior | 500 native | 100k prior | 100k native (provisional) | +|---|---:|---:|---:|---:| +| First 10 epochs: durable POST | 15.2 | 15.5 | 17.6 | 20.8 | +| Next 10 epochs: durable POST | 13.4 | 15.7 | 16.2 | 24.3 | +| First filter after the two saves: exactly 20 epochs | 31.1 | 21.9 | 119.2 | 124.5 | +| Two revision reads + two saves + filter | 73.6 | 66.9 | 166.0 | 217.5 | +| One cell: durable POST | 6.7 | 7.3 | 7.8 | 8.6 | +| Cell filter: exactly 100 inherited epochs | 41.5 | 39.7 | 129.8 | 156.8 | +| Cell AND epoch filter: exactly 10 epochs | 17.4 | 18.4 | 106.2 | 124.6 | +| Cell save + cell filter | 48.1 | 47.0 | 137.8 | 165.8 | + +The total uses paired per-cycle timings and includes both revision reads. POST timing ends only after canonical MySQL save acknowledgment. The separately scheduled recovery mirror is flushed and checked after the operations. These are Flask HTTP client timings on a disposable native MySQL database, not browser interaction or paint timings. + +The native run performs no preparatory tag filtering or SQLite tag checkpoint after seeding. Its very first filter request took 38.0 ms at 500 epochs and 984.3 ms at 100k; the first full sequences took 105.9 and 1074.7 ms. “First” means the first HTTP filter after seeding, not a cold MySQL/OS cache. The prior SQLite receipts prepared their tag caches before timing. Five samples do not establish tail-latency guarantees. + +## Index, persistence and correctness + +The actual 20-epoch filter uses the persistent `by_tag` covering index with `ref` access and an estimate of 20 lookup rows at both scales. Both runs distinguish `QC` from `qc` and NFC `é` from decomposed `é`, and verify AND, OR, NOT, inherited cell membership, direct-only epoch scope, exact author chips and revisions. Cell tagging changes one canonical cell record and creates no child annotation copies; both protocol curation scopes remain unchanged. + +The lookup is checkpointed and reopened as a fresh Python adapter in the same server, reusing the persistent SQL table. This is not a MySQL process restart. The reopened exact-20 filter takes 19.7/143.9 ms at 500/100k. Initial setup timing in the raw receipts is empty-database schema/trigger setup before seeding, not a populated-database migration benchmark. + +Both final backup receipts are `current`, with no pending/running work or error, and requested/completed sequence 34. The flushed recovery mirror matches all 63 tracked canonical records, including final removals. Both owned native servers stopped successfully. + +## Autocomplete diagnostic + +Two untimed-workflow diagnostic calls request `q=gate&limit=12`, checking exact counts and profile authors. Each is a single observation; “cold/warm” labels mean first/repeated endpoint calls after the timed workflow, not cold/warm storage. + +| Scale | First endpoint ms | Repeated endpoint ms | Aggregate SQL first/repeated ms | Author SQL first/repeated ms | +|---|---:|---:|---:|---:| +| 500 | 25.7 | 28.5 | 6.4 / 7.2 | 2.8 / 2.8 | +| 100,000 | 10202.6 | 9474.2 | 5976.9 / 5332.8 | 4200.6 / 4116.7 | + +At 100k, autocomplete scans the project-wide PRIMARY prefix (613,093 estimated rows) and filesorts for `COUNT(DISTINCT target_kind,target_uuid)` grouped by tag. The author subquery also selects PRIMARY project-prefix access instead of `by_tag`; the canonical join uses only project/kind (key length 111). These SQL operations account for essentially the entire 9–10 second endpoint latency. This remains a material responsiveness issue; it is separate from the indexed point-tag query. The raw receipts preserve actual SQL, timings and EXPLAIN output. + +## Reproducible evidence + +- [500-epoch native receipt](native-tag-sequence-pre-autocompletefix-500.json) and [100,000-epoch native receipt](native-tag-sequence-pre-autocompletefix-100000.json). +- [Prior 500-epoch receipt](tag-sequence-after-500.json) and [prior 100,000-epoch receipt](tag-sequence-after-100000.json). +- [Native harness](benchmark_native_tag_sequence.py) and [machine-readable comparison](native-tag-sequence-pre-autocompletefix-results.json). + +The 500-epoch source and harness inventories are unchanged. The 100k harness is unchanged, but `workspace_api.py`, `workspace_paths.py`, `workspace_projects.py`, and `tests/test_workspace_path_api.py` changed during execution. `tests/test_workspace_root_boundaries.py` also changed between scales. The raw receipt deliberately remains `passed: false`; its benchmark results must not be promoted to final unchanged-source evidence. Full before/after SHA-256 inventories and loaded-module paths are preserved. + +Native harness SHA-256: `a2b5e70861826936fdb4c9d6a5c76efd7645486ad5ce05e1482e3e6aab694fde`. + +These receipts validate this workflow and its stated checks; they do not certify a complete desktop release. diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-100000.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-100000.json new file mode 100644 index 0000000..c48255f --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-100000.json @@ -0,0 +1,3463 @@ +{ + "scope": "Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy.\n\nEvery project/database is disposable. Acquisition metadata is synthetic; actual\nMySQL, triggers, Flask routes, derived indexes and each version's save hooks\nare used. Native SQL commits are checked immediately; any background recovery\nmirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude\noracle work, and do not model browser concurrency/rendering. Sequential bundle\ntimes are sums of their separately measured requests. Profiles are separate.\n", + "epochs": 100000, + "profiles": 3, + "tags_per_annotation": 5, + "protocols": 2, + "samples": 5, + "source_root": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9", + "source_inventory_before": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3f4b346a59e1b78aeea51b1d1c2812582eed009b4cb2cc36831830e0d62601ca", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "a43e66ff47aaec64d0a862277b7751901775ab7f193f58c0106437b9fab1331b", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "fixture_module": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py", + "harness_sha256": "468173271c08020e7e1a7ce8b0fcdfc59693be0f9e3699a8caec342b2e77affd", + "started_at": "2026-09-30T15:17:46.744505+00:00", + "release_ready": false, + "operations": { + "first10_revision_preflight": { + "samples_seconds": [ + 0.01199199998518452, + 0.04156083398265764, + 0.007461917004548013, + 0.008337290957570076, + 0.006807041994761676 + ], + "p50_seconds": 0.008337290957570076, + "p95_seconds": 0.04156083398265764, + "p99_seconds": 0.04156083398265764, + "maximum_seconds": 0.04156083398265764, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + }, + { + "Bytes_sent": 15364, + "Questions": 4 + } + ] + }, + "first10_save": { + "samples_seconds": [ + 0.05614608299219981, + 0.02782075002323836, + 0.02499641600297764, + 0.02187658299226314, + 0.01975841698003933 + ], + "p50_seconds": 0.02499641600297764, + "p95_seconds": 0.05614608299219981, + "p99_seconds": 0.05614608299219981, + "maximum_seconds": 0.05614608299219981, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 18600, + "Questions": 36 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12424, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + } + ] + }, + "second10_revision_preflight": { + "samples_seconds": [ + 0.008524707984179258, + 0.006244334043003619, + 0.023840208014007658, + 0.005883166042622179, + 0.026213333010673523 + ], + "p50_seconds": 0.008524707984179258, + "p95_seconds": 0.026213333010673523, + "p99_seconds": 0.026213333010673523, + "maximum_seconds": 0.026213333010673523, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + }, + { + "Bytes_sent": 15382, + "Questions": 4 + } + ] + }, + "second10_save": { + "samples_seconds": [ + 0.023883083020336926, + 0.02518754097400233, + 0.02145470801042393, + 0.026714917039498687, + 0.019584666995797306 + ], + "p50_seconds": 0.023883083020336926, + "p95_seconds": 0.026714917039498687, + "p99_seconds": 0.026714917039498687, + "maximum_seconds": 0.026714917039498687, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12436, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 273985, + "Questions": 155 + } + ] + }, + "filter20": { + "samples_seconds": [ + 0.22716829099226743, + 0.12525804102187976, + 0.1252272499841638, + 0.13001949997851625, + 0.12601441703736782 + ], + "p50_seconds": 0.12601441703736782, + "p95_seconds": 0.22716829099226743, + "p99_seconds": 0.22716829099226743, + "maximum_seconds": 0.22716829099226743, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 141284, + "Questions": 64 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + }, + { + "Bytes_sent": 134745, + "Questions": 57 + } + ] + }, + "cell_save": { + "samples_seconds": [ + 0.010468583030160517, + 0.010496834001969546, + 0.008183291996829212, + 0.008193165995180607, + 0.008758000039961189 + ], + "p50_seconds": 0.008758000039961189, + "p95_seconds": 0.010496834001969546, + "p99_seconds": 0.010496834001969546, + "maximum_seconds": 0.010496834001969546, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4166, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + } + ] + }, + "filter_cell100": { + "samples_seconds": [ + 0.15443866699934006, + 0.16119712503859773, + 0.1600392499822192, + 0.1468521250062622, + 0.16326100000878796 + ], + "p50_seconds": 0.1600392499822192, + "p95_seconds": 0.16326100000878796, + "p99_seconds": 0.16326100000878796, + "maximum_seconds": 0.16326100000878796, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + }, + { + "Bytes_sent": 168054, + "Questions": 57 + } + ] + }, + "filter_cell_and_epoch10": { + "samples_seconds": [ + 0.12339312495896593, + 0.13643654203042388, + 0.12478045799070969, + 0.12551662500482053, + 0.12105583405354992 + ], + "p50_seconds": 0.12478045799070969, + "p95_seconds": 0.13643654203042388, + "p99_seconds": 0.13643654203042388, + "maximum_seconds": 0.13643654203042388, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + }, + { + "Bytes_sent": 125370, + "Questions": 58 + } + ] + }, + "remove_first10_revision_preflight": { + "samples_seconds": [ + 0.006872707977890968, + 0.006685125001240522, + 0.006732042005751282, + 0.006497750000562519, + 0.006534791027661413 + ], + "p50_seconds": 0.006685125001240522, + "p95_seconds": 0.006872707977890968, + "p99_seconds": 0.006872707977890968, + "maximum_seconds": 0.006872707977890968, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + } + ] + }, + "remove_first10_save": { + "samples_seconds": [ + 0.022132374986540526, + 0.024739916960243136, + 0.021291458979249, + 0.019143666955642402, + 0.02145708299940452 + ], + "p50_seconds": 0.02145708299940452, + "p95_seconds": 0.024739916960243136, + "p99_seconds": 0.024739916960243136, + "maximum_seconds": 0.024739916960243136, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12424, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + }, + { + "Bytes_sent": 12454, + "Questions": 29 + } + ] + }, + "filter_hierarchy_after_epoch_remove": { + "samples_seconds": [ + 0.11069879098795354, + 0.10966495797038078, + 0.10294529102975503, + 0.13921783299883828, + 0.10848212498240173 + ], + "p50_seconds": 0.10966495797038078, + "p95_seconds": 0.13921783299883828, + "p99_seconds": 0.13921783299883828, + "maximum_seconds": 0.13921783299883828, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + }, + { + "Bytes_sent": 112902, + "Questions": 55 + } + ] + }, + "filter_remaining10": { + "samples_seconds": [ + 0.11796779197175056, + 0.11772724997717887, + 0.1194367500138469, + 0.12223120802082121, + 0.15665787504985929 + ], + "p50_seconds": 0.1194367500138469, + "p95_seconds": 0.15665787504985929, + "p99_seconds": 0.15665787504985929, + "maximum_seconds": 0.15665787504985929, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + }, + { + "Bytes_sent": 124605, + "Questions": 57 + } + ] + }, + "remove_second10_revision_preflight": { + "samples_seconds": [ + 0.01008412498049438, + 0.010636958002578467, + 0.00979362498037517, + 0.00988920801319182, + 0.010092334006913006 + ], + "p50_seconds": 0.01008412498049438, + "p95_seconds": 0.010636958002578467, + "p99_seconds": 0.010636958002578467, + "maximum_seconds": 0.010636958002578467, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + }, + { + "Bytes_sent": 15802, + "Questions": 4 + } + ] + }, + "remove_second10_save": { + "samples_seconds": [ + 0.023356417019385844, + 0.021738334035035223, + 0.018369458965025842, + 0.020638792018871754, + 0.019545999995898455 + ], + "p50_seconds": 0.020638792018871754, + "p95_seconds": 0.023356417019385844, + "p99_seconds": 0.023356417019385844, + "maximum_seconds": 0.023356417019385844, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12436, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + }, + { + "Bytes_sent": 12466, + "Questions": 29 + } + ] + }, + "filter_after_all_epoch_removals": { + "samples_seconds": [ + 0.10815216699847952, + 0.10508224996738136, + 0.1046494580223225, + 0.10758879204513505, + 0.1083835830213502 + ], + "p50_seconds": 0.10758879204513505, + "p95_seconds": 0.1083835830213502, + "p99_seconds": 0.1083835830213502, + "maximum_seconds": 0.1083835830213502, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + } + ] + }, + "remove_cell_save": { + "samples_seconds": [ + 0.009546625020448118, + 0.008671040995977819, + 0.008816290996037424, + 0.008307332987897098, + 0.009664583019912243 + ], + "p50_seconds": 0.008816290996037424, + "p95_seconds": 0.009664583019912243, + "p99_seconds": 0.009664583019912243, + "maximum_seconds": 0.009664583019912243, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4166, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + }, + { + "Bytes_sent": 4169, + "Questions": 11 + } + ] + }, + "filter_after_cell_removal": { + "samples_seconds": [ + 0.1054909999947995, + 0.10503399994922802, + 0.10871112497989088, + 0.10642904101405293, + 0.10895304195582867 + ], + "p50_seconds": 0.10642904101405293, + "p95_seconds": 0.10895304195582867, + "p99_seconds": 0.10895304195582867, + "maximum_seconds": 0.10895304195582867, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + }, + { + "Bytes_sent": 112145, + "Questions": 54 + } + ] + }, + "tag10_then10_filter20_http_total": { + "samples_seconds": [ + 0.32771416497416794, + 0.22607150004478171, + 0.20298049901612103, + 0.19283145701047033, + 0.19837787601863965 + ], + "p50_seconds": 0.20298049901612103, + "p95_seconds": 0.32771416497416794, + "p99_seconds": 0.32771416497416794, + "maximum_seconds": 0.32771416497416794, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "cell_tag_then_cell_filter_http_total": { + "samples_seconds": [ + 0.16490725002950057, + 0.17169395904056728, + 0.1682225419790484, + 0.15504529100144282, + 0.17201900004874915 + ], + "p50_seconds": 0.1682225419790484, + "p95_seconds": 0.17201900004874915, + "p99_seconds": 0.17201900004874915, + "maximum_seconds": 0.17201900004874915, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "first10_selected_action_http_total": { + "samples_seconds": [ + 0.06813808297738433, + 0.069381584005896, + 0.03245833300752565, + 0.030213873949833214, + 0.026565458974801004 + ], + "p50_seconds": 0.03245833300752565, + "p95_seconds": 0.069381584005896, + "p99_seconds": 0.069381584005896, + "maximum_seconds": 0.069381584005896, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "second10_selected_action_http_total": { + "samples_seconds": [ + 0.032407791004516184, + 0.03143187501700595, + 0.045294916024431586, + 0.032598083082120866, + 0.04579800000647083 + ], + "p50_seconds": 0.032598083082120866, + "p95_seconds": 0.04579800000647083, + "p99_seconds": 0.04579800000647083, + "maximum_seconds": 0.04579800000647083, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "autocomplete_cold_diagnostic": { + "samples_seconds": [ + 3.740355083020404 + ], + "p50_seconds": 3.740355083020404, + "p95_seconds": 3.740355083020404, + "p99_seconds": 3.740355083020404, + "maximum_seconds": 3.740355083020404, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 215741, + "Questions": 91 + } + ] + }, + "autocomplete_warm_diagnostic": { + "samples_seconds": [ + 3.255884749989491 + ], + "p50_seconds": 3.255884749989491, + "p95_seconds": 3.255884749989491, + "p99_seconds": 3.255884749989491, + "maximum_seconds": 3.255884749989491, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 215741, + "Questions": 91 + } + ] + }, + "autocomplete_empty_diagnostic": { + "samples_seconds": [ + 11.217491208051797 + ], + "p50_seconds": 11.217491208051797, + "p95_seconds": 11.217491208051797, + "p99_seconds": 11.217491208051797, + "maximum_seconds": 11.217491208051797, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 219196, + "Questions": 91 + } + ] + }, + "same_server_native_reuse_filter20": { + "samples_seconds": [ + 0.13854400004493073 + ], + "p50_seconds": 0.13854400004493073, + "p95_seconds": 0.13854400004493073, + "p99_seconds": 0.13854400004493073, + "maximum_seconds": 0.13854400004493073, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 134746, + "Questions": 57 + } + ] + } + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 33334 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 66666 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 66667 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "page_cells": true, + "target_specification": "tag10_then10_filter20_and_cell_epoch_hierarchy", + "baseline_harness_sha256": "272fe050c8762ed4ea45bd013e236e8723d8fe46f5e7e293c58e2edf1fd52ddc", + "mysql_version": "8.4.2", + "seed_seconds": 127.78472875000443, + "seed_checkpoint_seconds": 13.33677566703409, + "native_lookup_startup_preparation": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 1.488408 + } + }, + "project_uuid": "3a791e27-101f-4a82-a7e8-f8be38297694", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 1.672049 + }, + "selected_epoch_uuids": { + "first10": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5" + ], + "second10": [ + "ad573668-6512-6e55-649e-cb23ae1d4888", + "16dc368a-89b4-28b2-4854-84313ba67a39", + "37834f2f-2576-2f23-e1f7-4a531cbe445d", + "454f63ac-30c8-3229-97ef-025edff6abd2", + "5ef6fdf3-2513-aa7c-d11f-72beccf132b9", + "1253e937-3e78-1b75-0026-6caa55150e08", + "482d9673-cfee-5de3-91f9-7fde4d1c84f9", + "3346f2bb-f6c3-4bd2-dbe2-8bd1bb657d0e", + "9537f32e-c759-9e1a-e953-af6c9f929fe7", + "0fd42b3f-73c4-48b3-4940-b339f87d07ad" + ], + "cell": "3bb78535-cc95-55ff-19fe-3556aaa41c78", + "cell_children": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5", + "4a44dc15-3642-04a8-0fe8-0e9039455cc1", + "4fc82b26-aecb-47d2-868c-4efbe3581732", + "6b51d431-df5d-7f14-1cbe-ceccf79edf3d", + "3fdba35f-04dc-8c46-2986-c992bcf87554", + "8527a891-e224-1369-50ff-32ca212b45bc", + "e629fa65-98d7-3276-8f7c-726b4b621285", + "b17ef6d1-9c7a-5b1e-e83b-907c595526dc", + "4523540f-1504-cd17-100c-4835e85b7eef", + "4ec9599f-c203-d176-a301-536c2e091a19", + "9400f1b2-1cb5-27d7-fa3d-3eabba93557a", + "f5ca38f7-48a1-d6ea-f726-b8a42fb575c3", + "6f4b6612-125f-b3a0-daec-d2799dfd6c9c", + "785f3ec7-eb32-f30b-90cd-0fcf3657d388", + "535fa30d-7e25-dd8a-49f1-536779734ec8", + "c2356069-e9d1-e79c-a924-378153cfbbfb", + "b7a56873-cd77-1f2c-446d-369b649430b6", + "5f9c4ab0-8cac-7457-e911-1a30e4664920", + "670671cd-9740-4156-226e-507973f2ab83", + "59e19706-d51d-39f6-6711-c2653cd7eb12", + "35135aaa-6cc2-3891-b40c-b3f378c53a17", + "624b60c5-8c9d-8bfb-6ff1-886c2fd605d2", + "eb1e33e8-a81b-697b-7585-5af6bfcdbcbf", + "e29c9c18-0c62-79b0-b02a-bd6a1801c7c0", + "c6f3ac57-944a-5314-90cd-39902d0f7777", + "86e50149-6586-6131-2a9e-0b35558d84f6", + "9f14025a-f006-5b30-e47e-23ebb3b491d3", + "76a50887-d8f1-c2e9-3017-55428990ad81", + "7a61b537-01be-fdae-0eee-ffaecc73f14e", + "aea92132-c4cb-eb26-3e6a-c2bf6c183b5d", + "0b918943-df09-62bc-7a18-24c0555a3893", + "d59eced1-ded0-7f84-c145-592f65bdf854", + "3d914f93-48c9-cc0f-f8a7-9716700b9fcd", + "73475cb4-0a56-8e8d-a8a0-45ced110137e", + "44cb730c-4204-80a0-477b-505ae68af508", + "71ee45a3-c0db-9a98-65f7-313dd3372cf6", + "811786ad-1ae7-4adf-dd20-dd0372abaaeb", + "25fc0e70-96fc-6537-1820-2dc30b0c580b", + "31489056-e091-6d59-fe3a-dd79e63f095a", + "98010bd9-270f-9b10-0b62-14a21754fd33", + "0e17daca-5f3e-175f-448b-acace3bc0da4", + "1a656259-0ef1-9d10-45d0-6c4055742d38", + "031b4af5-197e-c30a-926f-48cf40e11a7d", + "41cfc0d1-f2d1-27b0-4555-b7246d84019b", + "2858dcd1-057d-3eae-7f7d-5f782167e24b", + "2fca346d-b656-1871-02ce-806ac732e06a", + "02d20bbd-7e39-4ad5-999a-4cebabac9619", + "7688b6ef-5255-5962-d008-fff894223582", + "c837649c-ce43-f272-9138-e72cc3152070", + "6208ef0f-7750-c111-548c-f90b6ea1d0d0", + "3e1e967e-9b79-3e90-8f8e-ae83c74dba9b", + "39fa9ec1-90ee-e7b6-f4df-f1100d6343e1", + "d029fa3a-95e1-74a1-9934-857f535eb942", + "81b8a03f-97e8-787c-53fe-1a86bda042b6", + "da4ea2a5-506f-2693-eae1-90d9360a1f31", + "a68b412c-4282-555f-1554-6cf6e1fc4289", + "108c995b-953c-8a35-5611-03e2014cf828", + "3ada92f2-8b4c-eda3-8562-ebf047c6ff05", + "49d180ec-f561-3281-9571-bf39d9b7b342", + "a21855da-08cb-102d-1d21-7c53dc5824a3", + "c75cb66a-e28d-8ebc-6ede-d002c28a8ba0", + "ff5a1ae0-12af-a5d4-c889-c50ad427aaf5", + "7f2253d7-e228-b22a-08bd-a1f09c516f6f", + "87226162-0421-7edd-b39e-7df969e0698a", + "96061e92-f58e-4bdc-dee7-3df36183fe3a", + "eb624dbe-56eb-6620-ae62-080c10a273ca", + "f369cb89-fc62-7e66-8987-007d121ed1ea", + "f74efabe-f12e-a619-e30b-79bddef89cff", + "a88a7902-cb4e-f697-ba0b-6759c50e8c10", + "349c4120-1b62-db85-1192-665c504b350f", + "98a3ab7c-340e-8a03-3e7b-37b6ef942875", + "48449a14-a4ff-7d79-bb7a-1b6f3d488eba", + "5316ca1c-5ddc-a8e6-cecc-fce58f3b8540", + "a46e3763-2fa6-ca51-a13f-e39a567b3c23", + "bbb965ab-0c80-d653-8cf2-184babad2a56", + "44c8031c-b036-a735-0d8b-9b8603af662a", + "b4944c6f-f08d-c6f4-3da2-e9c824669b7d", + "434c9b5a-e514-646b-bd91-b50032ca579e", + "bdd2d3af-3a5a-1213-497d-4f1f7bfcda89", + "8b940be7-fb78-aaa6-b656-7dd7a3987996", + "cd70bea0-23f7-52a0-564a-bb6ed08d42c1", + "69f59c27-3b6e-669a-c32a-6dd5e1b2cb63", + "1da51b8d-8ff9-8f6a-48f8-0ae79fe3ca6c", + "82416496-09f8-8ccd-2a0a-5b233a07a538", + "6e400187-1c0c-f27c-7634-ef1dc478408f", + "e3d6c4d4-599e-0088-2384-ca981ee287ed", + "ad48ff99-415b-2f00-7dc3-5b7eb553fd1e", + "7b1a278f-5abe-8e9d-a907-fc9c29dfd432", + "d6d824ab-ba4a-fde8-1129-c71dea75b810", + "29db0c67-82db-d500-0559-ef4d9e953e30", + "8c1f1046-219d-dd21-6a02-3f792356ddf1" + ] + }, + "backup_receipts": [ + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 1, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 2, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 3, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 4, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 5, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 6, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 7, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 8, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 9, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 10, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 11, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 12, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 13, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 14, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 15, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 16, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 17, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 18, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 19, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 20, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 21, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 22, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 23, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 24, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 25, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 12, + "last_error": null, + "last_success": "2026-09-30T15:20:48.778388+00:00", + "pending": true, + "requested_sequence": 26, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 26, + "last_error": null, + "last_success": "2026-09-30T15:20:54.339162+00:00", + "pending": true, + "requested_sequence": 27, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 26, + "last_error": null, + "last_success": "2026-09-30T15:20:54.339162+00:00", + "pending": true, + "requested_sequence": 28, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 26, + "last_error": null, + "last_success": "2026-09-30T15:20:54.339162+00:00", + "pending": true, + "requested_sequence": 29, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 26, + "last_error": null, + "last_success": "2026-09-30T15:20:54.339162+00:00", + "pending": true, + "requested_sequence": 30, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_first10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:20:56.802369+00:00", + "pending": true, + "requested_sequence": 31, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_second10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:20:56.802369+00:00", + "pending": true, + "requested_sequence": 32, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_first10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:21:15.996011+00:00", + "pending": true, + "requested_sequence": 33, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_second10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:21:15.996011+00:00", + "pending": true, + "requested_sequence": 34, + "running": false, + "status": "pending" + }, + "database": "committed" + } + } + ], + "preparation_index_seconds": 0, + "lookup_mode": "persistent_native_sql_no_post_seed_tag_cache_preparation", + "bundle_definitions": { + "tag10_then10_filter20_http_total": [ + "first10_revision_preflight", + "first10_save", + "second10_revision_preflight", + "second10_save", + "filter20" + ], + "cell_tag_then_cell_filter_http_total": [ + "cell_save", + "filter_cell100" + ], + "first10_selected_action_http_total": [ + "first10_revision_preflight", + "first10_save" + ], + "second10_selected_action_http_total": [ + "second10_revision_preflight", + "second10_save" + ] + }, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:21:20.833735+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 3.526624999998603 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.08437079098075628 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.10236137500032783 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0004254169762134552 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 3.0357274590060115 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.09343941701808944 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.1018385419738479 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0004039999912492931 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 2.991644333000295 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 4.095707458036486 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 4.103170584014151 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0005604579928331077 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "38", + "ref": "const", + "rows": 827077, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 204390, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 204390, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 2951014, + "filtered": 100.0, + "Extra": "Using where; Using index for group-by (scanning)" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "index", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 1654154, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 12, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "filter20_cpu_profile": { + "top_functions": [ + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 331, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.6042000000000004e-05, + "cumulative_seconds": 0.338109625 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 159, + "function": "request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.333e-06, + "cumulative_seconds": 0.3380305 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1163, + "function": "get", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.6660000000000005e-06, + "cumulative_seconds": 0.337179375 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/testing.py", + "line": 204, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.3209e-05, + "cumulative_seconds": 0.33717370900000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1062, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.164000000000001e-06, + "cumulative_seconds": 0.33688270800000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 984, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0458e-05, + "cumulative_seconds": 0.336865792 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1230, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.958e-06, + "cumulative_seconds": 0.336662834 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1529, + "function": "__call__", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.625e-06, + "cumulative_seconds": 0.33663787500000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1479, + "function": "wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.2791000000000003e-05, + "cumulative_seconds": 0.33663125000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 904, + "function": "full_dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.124e-06, + "cumulative_seconds": 0.33631266600000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 879, + "function": "dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.00011029200000000001, + "cumulative_seconds": 0.33607037500000003 + }, + { + "file": "python/workspace_api.py", + "line": 716, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.00012362900000000002, + "cumulative_seconds": 0.335955334 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 27, + "calls": 38, + "self_seconds": 3.4711e-05, + "cumulative_seconds": 0.153796711 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 249, + "function": "native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.4042e-05, + "cumulative_seconds": 0.153727834 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 268, + "function": "_native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.3998e-05, + "cumulative_seconds": 0.136067916 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 311, + "function": "native_context", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 5.1705e-05, + "cumulative_seconds": 0.135981292 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 207, + "function": "_metadata_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 0.009798792, + "cumulative_seconds": 0.13164345800000002 + }, + { + "file": "python/workspace_service.py", + "line": 748, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.0008182500000000001, + "cumulative_seconds": 0.12887279100000001 + }, + { + "file": "python/workspace_service.py", + "line": 778, + "function": "_epoch_page_identities", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.007877548, + "cumulative_seconds": 0.12800725000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 22, + "calls": 4058, + "self_seconds": 0.0012614710000000001, + "cumulative_seconds": 0.12213162500000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 212, + "function": "", + "primitive_calls": 18, + "calls": 18, + "self_seconds": 2.7666000000000002e-05, + "cumulative_seconds": 0.121835333 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 55, + "function": "_epoch_query_equal", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 0.09261957500000001, + "cumulative_seconds": 0.115141374 + }, + { + "file": "python/workspace_annotations.py", + "line": 261, + "function": "filter_epoch_ids", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.019374498, + "cumulative_seconds": 0.098126458 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 132, + "function": "__enter__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 2.376e-06, + "cumulative_seconds": 0.080341042 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 141, + "function": "__exit__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 8.042e-06, + "cumulative_seconds": 0.073394875 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 8, + "function": "matching", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.045571507000000004, + "cumulative_seconds": 0.068809667 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 322, + "function": "traced_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000242801, + "cumulative_seconds": 0.035812709000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 412, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000141084, + "cumulative_seconds": 0.035118955 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 402, + "function": "_execute_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00012974700000000002, + "cumulative_seconds": 0.034778042 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 150, + "function": "execute", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.379500000000001e-05, + "cumulative_seconds": 0.034351083000000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 332, + "function": "_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.8946e-05, + "cumulative_seconds": 0.033850826 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 575, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 9.021300000000001e-05, + "cumulative_seconds": 0.033317961 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 851, + "function": "_read_query_result", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.0452e-05, + "cumulative_seconds": 0.031795709000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1288, + "function": "read", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 8.0127e-05, + "cumulative_seconds": 0.031705006 + }, + { + "file": "python/workspace_annotations.py", + "line": 295, + "function": "for_epochs", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000124575, + "cumulative_seconds": 0.026587167000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 535040, + "calls": 535040, + "self_seconds": 0.0250952, + "cumulative_seconds": 0.0250952 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 763, + "function": "_read_packet", + "primitive_calls": 765, + "calls": 765, + "self_seconds": 0.0012484330000000002, + "cumulative_seconds": 0.022685774000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 813, + "function": "_read_bytes", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.000573005, + "cumulative_seconds": 0.019514024 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 869, + "function": "to_dicts", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.8583e-05, + "cumulative_seconds": 0.019235625000000003 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.00022469000000000002, + "cumulative_seconds": 0.018863232 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/socket.py", + "line": 704, + "function": "readinto", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 8.7658e-05, + "cumulative_seconds": 0.018638542 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1299, + "function": "recv_into", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 8.548900000000001e-05, + "cumulative_seconds": 0.018509461 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1157, + "function": "read", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 4.6499e-05, + "cumulative_seconds": 0.018414708000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 0.018363831, + "cumulative_seconds": 0.018363831 + }, + { + "file": "python/workspace_state_generation.py", + "line": 101, + "function": "_rows", + "primitive_calls": 46, + "calls": 46, + "self_seconds": 6.0753000000000006e-05, + "cumulative_seconds": 0.017847586000000002 + }, + { + "file": "python/workspace_state_generation.py", + "line": 197, + "function": "response_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.8416e-05, + "cumulative_seconds": 0.0175995 + }, + { + "file": "python/workspace_state_generation.py", + "line": 233, + "function": "_attest_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 6.2878e-05, + "cumulative_seconds": 0.017564833000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/__init__.py", + "line": 138, + "function": "jsonify", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0375000000000001e-05, + "cumulative_seconds": 0.017006875 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 189, + "function": "response", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.7917e-05, + "cumulative_seconds": 0.016991125000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 1231, + "function": "cursor", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.1545e-05, + "cumulative_seconds": 0.016985083 + }, + { + "file": "python/workspace_api.py", + "line": 61, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.4667000000000004e-05, + "cumulative_seconds": 0.016911167 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 128, + "function": "deepcopy", + "primitive_calls": 78, + "calls": 17170, + "self_seconds": 0.009457589, + "cumulative_seconds": 0.016118456 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 201, + "function": "_deepcopy_list", + "primitive_calls": 62, + "calls": 102, + "self_seconds": 0.000297197, + "cumulative_seconds": 0.015986214000000002 + }, + { + "file": "python/workspace_api.py", + "line": 62, + "function": "browser_safe", + "primitive_calls": 1, + "calls": 9641, + "self_seconds": 0.003125787, + "cumulative_seconds": 0.015383334 + }, + { + "file": "python/workspace_api.py", + "line": 66, + "function": "", + "primitive_calls": 1, + "calls": 1363, + "self_seconds": 0.011160961, + "cumulative_seconds": 0.015381166000000002 + }, + { + "file": "python/workspace_api.py", + "line": 68, + "function": "", + "primitive_calls": 2, + "calls": 102, + "self_seconds": 0.000217979, + "cumulative_seconds": 0.015366791000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 227, + "function": "_deepcopy_dict", + "primitive_calls": 1242, + "calls": 1284, + "self_seconds": 0.002889378, + "cumulative_seconds": 0.014004211 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1370, + "function": "_read_result_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.5784e-05, + "cumulative_seconds": 0.012644917 + }, + { + "file": "python/workspace_service.py", + "line": 845, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.011560791, + "cumulative_seconds": 0.011560791 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 34, + "function": "_exact_equal", + "primitive_calls": 22, + "calls": 14072, + "self_seconds": 0.0036541620000000003, + "cumulative_seconds": 0.010249251000000001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 134, + "function": "_active_ddl_guard", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 3.4085e-05, + "cumulative_seconds": 0.009855583000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1416, + "function": "_read_rowdata_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00036018300000000003, + "cumulative_seconds": 0.009693584 + }, + { + "file": "python/workspace_service.py", + "line": 797, + "function": "", + "primitive_calls": 100001, + "calls": 100001, + "self_seconds": 0.009644538000000001, + "cumulative_seconds": 0.009644538000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 173, + "function": "_rows", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.5997e-05, + "cumulative_seconds": 0.009355959 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 101, + "function": "selected", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.4914000000000002e-05, + "cumulative_seconds": 0.0076009580000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1429, + "function": "_read_row_from_packet", + "primitive_calls": 428, + "calls": 428, + "self_seconds": 0.000937469, + "cumulative_seconds": 0.007531751000000001 + }, + { + "file": "python/workspace_curation.py", + "line": 170, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.334e-06, + "cumulative_seconds": 0.007453250000000001 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 42, + "function": "", + "primitive_calls": 6012, + "calls": 16026, + "self_seconds": 0.004263462, + "cumulative_seconds": 0.007246141 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 100027, + "calls": 100027, + "self_seconds": 0.005727994, + "cumulative_seconds": 0.005727994 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 205717, + "calls": 205719, + "self_seconds": 0.005396692000000001, + "cumulative_seconds": 0.005397149 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 68, + "function": "", + "primitive_calls": 21, + "calls": 21, + "self_seconds": 0.004913249000000001, + "cumulative_seconds": 0.004913249000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/converters.py", + "line": 166, + "function": "convert_datetime", + "primitive_calls": 144, + "calls": 144, + "self_seconds": 0.004578714, + "cumulative_seconds": 0.0048093780000000004 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 100008, + "calls": 100008, + "self_seconds": 0.004321989, + "cumulative_seconds": 0.004321989 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 38, + "function": "walk", + "primitive_calls": 1, + "calls": 2, + "self_seconds": 0.001046209, + "cumulative_seconds": 0.00395225 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 68, + "function": "", + "primitive_calls": 10, + "calls": 10, + "self_seconds": 9.625e-06, + "cumulative_seconds": 0.0035925830000000003 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 44, + "function": "", + "primitive_calls": 2040, + "calls": 2040, + "self_seconds": 0.000445773, + "cumulative_seconds": 0.0034728270000000004 + }, + { + "file": "python/workspace_state_generation.py", + "line": 107, + "function": "_ddl", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 3.1046e-05, + "cumulative_seconds": 0.0033254160000000003 + }, + { + "file": "python/workspace_state_generation.py", + "line": 125, + "function": "_observer_status", + "primitive_calls": 8, + "calls": 8, + "self_seconds": 3.1999e-05, + "cumulative_seconds": 0.003297042 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 106471, + "calls": 106471, + "self_seconds": 0.003258059, + "cumulative_seconds": 0.003258059 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1448, + "function": "_get_descriptions", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000333447, + "cumulative_seconds": 0.0028627550000000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 185, + "function": "_metadata", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.4043000000000005e-05, + "cumulative_seconds": 0.002859917 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 0.002604916, + "cumulative_seconds": 0.002604916 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 163, + "function": "read_length_coded_string", + "primitive_calls": 2712, + "calls": 2712, + "self_seconds": 0.000841616, + "cumulative_seconds": 0.002495883 + }, + { + "file": "python/workspace_state_generation.py", + "line": 115, + "function": "_triggers", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.333e-06, + "cumulative_seconds": 0.0024841250000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 898, + "function": "", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 6.1905e-05, + "cumulative_seconds": 0.002217292 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 899, + "function": "", + "primitive_calls": 86, + "calls": 86, + "self_seconds": 0.000381109, + "cumulative_seconds": 0.001893382 + }, + { + "file": "python/workspace_explorer.py", + "line": 60, + "function": "protocol_binding_header", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 2.4292e-05, + "cumulative_seconds": 0.001865792 + }, + { + "file": "python/workspace_annotations.py", + "line": 195, + "function": "_chips", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 4.2914e-05, + "cumulative_seconds": 0.001833713 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 183, + "function": "dumps", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 3.6248e-05, + "cumulative_seconds": 0.0017533330000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 183, + "function": "encode", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.9416e-05, + "cumulative_seconds": 0.0017009590000000002 + }, + { + "file": "python/workspace_native_tag_filter.py", + "line": 25, + "function": "contains", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 7.124000000000001e-06, + "cumulative_seconds": 0.0016989580000000002 + }, + { + "file": "python/workspace_annotations.py", + "line": 188, + "function": "_validated_tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.559e-05, + "cumulative_seconds": 0.001677466 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 205, + "function": "iterencode", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 0.001668041, + "cumulative_seconds": 0.001668041 + }, + { + "file": "python/workspace_native_tag_lookup.py", + "line": 251, + "function": "targets", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0126000000000001e-05, + "cumulative_seconds": 0.0016652090000000002 + }, + { + "file": "python/workspace_native_tag_lookup.py", + "line": 93, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.207e-06, + "cumulative_seconds": 0.001634208 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 232, + "function": "__init__", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 8.9801e-05, + "cumulative_seconds": 0.0015738780000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 166, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.040000000000001e-06, + "cumulative_seconds": 0.0014831660000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 236, + "function": "_parse_field_descriptor", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 0.000327473, + "cumulative_seconds": 0.001460918 + }, + { + "file": "python/workspace_service.py", + "line": 236, + "function": "source_scope", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 4.0004000000000005e-05, + "cumulative_seconds": 0.001446042 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 869, + "function": "_execute_command", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000467089, + "cumulative_seconds": 0.001418542 + } + ], + "native_sql_calls": [ + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0011297910241410136 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004975830088369548 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00027316599152982235 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00042937498074024916 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002436659997329116 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003595830057747662 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.000341000035405159 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00013645802391692996 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00022445799550041556 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00017604202730581164 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00047745800111442804 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.001228584034834057 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003522090264596045 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00017862499225884676 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00038754200795665383 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00020529201719909906 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003262920072302222 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0004046669928357005 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.0001313749817200005 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00022350001381710172 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0005449579912237823 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00022733403602615 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00019225000869482756 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.0006037919665686786 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0006285419804044068 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00047687499318271875 + }, + { + "thread": "filter", + "sql_shape": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "seconds": 0.0016202910337597132 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`epoch_uuid`,`included`,`tags`,`review_state`,`revision`,`metadata_fingerprint` FROM `recording_workspace`.`curation` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))AND( ( (`epoch_uuid`='?') OR (", + "seconds": 0.006371416035108268 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`dataset_uuid`,`created_at`,`artifact_sha256` FROM `recording_workspace`.`dataset_revision` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0006397080142050982 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.006264208001084626 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.0007439159671775997 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00044420798076316714 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00020970799960196018 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00025345798349007964 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0004218749818392098 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0008576669497415423 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0005532079958356917 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00023662502644583583 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00042770797153934836 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00023695797426626086 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003593750298023224 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00039854203350842 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00016325002070516348 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00025037501472979784 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00019079202320426702 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005356249748729169 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.001245874969754368 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00038291700184345245 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00020591699285432696 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0003889590152539313 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00021708401618525386 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.000338125042617321 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0002839590306393802 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.0001384170027449727 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00024216703604906797 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0006391250062733889 + } + ], + "limits": "Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap." + }, + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.068396 + } + }, + "project_uuid": "3a791e27-101f-4a82-a7e8-f8be38297694", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.151797 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.052229 + } + }, + "project_uuid": "3a791e27-101f-4a82-a7e8-f8be38297694", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.165251 + }, + "seconds": 0.31707962503423914, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "workflow_peak_rss_before_durable_oracle_bytes": 953991168, + "durable_snapshot_verify_seconds": 8.305504375020973, + "loaded_product_modules": { + "workspace_tree": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tree.py", + "workspace_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_predicates.py", + "workspace_cache_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_cache_lifecycle.py", + "workspace_metadata_objects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_metadata_objects.py", + "workspace_disk_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_disk_index.py", + "workspace_catalog_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_catalog_identity.py", + "recording_workspace": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/recording_workspace.py", + "workspace_recipes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_recipes.py", + "workspace_tree_code": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tree_code.py", + "workspace_service": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_service.py", + "workspace_tree_pages": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tree_pages.py", + "workspace_projects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_projects.py", + "workspace_mysql_profile": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_mysql_profile.py", + "workspace_native_mysql": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_native_mysql.py", + "workspace_mysql_runtime": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_mysql_runtime.py", + "workspace_storage": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_storage.py", + "workspace_diff": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_diff.py", + "workspace_protocol_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_protocol_identity.py", + "workspace_import_check": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_import_check.py", + "workspace_audit": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_audit.py", + "workspace_api": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_api.py", + "workspace_state_snapshot": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_state_snapshot.py", + "workspace_author_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_author_preferences.py", + "workspace_curation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_curation.py", + "workspace_annotations": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_annotations.py", + "workspace_shared_tag_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_shared_tag_index.py", + "workspace_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_paths.py", + "workspace_desktop_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_desktop_paths.py", + "workspace_startup_registry": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_startup_registry.py", + "workspace_explorer": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_explorer.py", + "workspace_datastores": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_datastores.py", + "workspace_suggestions": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_suggestions.py", + "workspace_tag_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tag_predicates.py", + "workspace_export_folder": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_export_folder.py", + "workspace_import_progress": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_import_progress.py", + "workspace_project_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_project_preferences.py", + "workspace_protocol_state": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_protocol_state.py", + "workspace_state_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_state_generation.py", + "workspace_project_servers": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_project_servers.py", + "workspace_launcher": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_launcher.py", + "workspace_app_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_app_routes.py", + "workspace_folder_browser": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_folder_browser.py", + "workspace_h5_inbox": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_h5_inbox.py", + "workspace_tag_exchange": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tag_exchange.py", + "workspace_external_tags": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_external_tags.py", + "workspace_qc": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_qc.py", + "workspace_search": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_search.py", + "workspace_matlab_masks": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_matlab_masks.py", + "workspace_matlab_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_matlab_routes.py", + "workspace_mask_refresh": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_mask_refresh.py", + "workspace_matching_epochs": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_matching_epochs.py", + "workspace_candidate_exports": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_candidate_exports.py", + "workspace_backup_scheduler": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_backup_scheduler.py", + "workspace_recovery_store": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_recovery_store.py", + "workspace_recovery_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_recovery_generation.py", + "workspace_annotation_preparation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_annotation_preparation.py", + "workspace_native_tag_lookup": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_native_tag_lookup.py", + "workspace_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_lifecycle.py", + "workspace_native_tag_filter": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_native_tag_filter.py" + }, + "owned_native_runtime_stopped": true, + "source_inventory_after": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3f4b346a59e1b78aeea51b1d1c2812582eed009b4cb2cc36831830e0d62601ca", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "a43e66ff47aaec64d0a862277b7751901775ab7f193f58c0106437b9fab1331b", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "source_unchanged": true, + "harness_unchanged": true, + "seconds": 223.9138767500408, + "finished_at": "2026-09-30T15:21:30.662101+00:00", + "peak_rss_bytes": 953991168, + "passed": true +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-500.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-500.json new file mode 100644 index 0000000..1ac3681 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-500.json @@ -0,0 +1,3463 @@ +{ + "scope": "Persistent native tag lookup: tag-ten, tag-another-ten, filter-twenty and cell/epoch hierarchy.\n\nEvery project/database is disposable. Acquisition metadata is synthetic; actual\nMySQL, triggers, Flask routes, derived indexes and each version's save hooks\nare used. Native SQL commits are checked immediately; any background recovery\nmirror is explicitly flushed before its final oracle. HTTP times include Flask serialization/client JSON decoding, exclude\noracle work, and do not model browser concurrency/rendering. Sequential bundle\ntimes are sums of their separately measured requests. Profiles are separate.\n", + "epochs": 500, + "profiles": 3, + "tags_per_annotation": 5, + "protocols": 2, + "samples": 5, + "source_root": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9", + "source_inventory_before": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3f4b346a59e1b78aeea51b1d1c2812582eed009b4cb2cc36831830e0d62601ca", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "a43e66ff47aaec64d0a862277b7751901775ab7f193f58c0106437b9fab1331b", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "fixture_module": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py", + "harness_sha256": "468173271c08020e7e1a7ce8b0fcdfc59693be0f9e3699a8caec342b2e77affd", + "started_at": "2026-09-30T15:17:16.330782+00:00", + "release_ready": false, + "operations": { + "first10_revision_preflight": { + "samples_seconds": [ + 0.006863583053927869, + 0.005767875001765788, + 0.005951334023848176, + 0.006857750006020069, + 0.006089958013035357 + ], + "p50_seconds": 0.006089958013035357, + "p95_seconds": 0.006863583053927869, + "p99_seconds": 0.006863583053927869, + "maximum_seconds": 0.006863583053927869, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15362, + "Questions": 4 + }, + { + "Bytes_sent": 15362, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + }, + { + "Bytes_sent": 15363, + "Questions": 4 + } + ] + }, + "first10_save": { + "samples_seconds": [ + 0.03397225000662729, + 0.01669733296148479, + 0.01590783294523135, + 0.01774270902387798, + 0.018389292003121227 + ], + "p50_seconds": 0.01774270902387798, + "p95_seconds": 0.03397225000662729, + "p99_seconds": 0.03397225000662729, + "maximum_seconds": 0.03397225000662729, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 18598, + "Questions": 36 + }, + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12423, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + } + ] + }, + "second10_revision_preflight": { + "samples_seconds": [ + 0.006374125019647181, + 0.005576791998464614, + 0.006221582996658981, + 0.0060125000309199095, + 0.005592082976363599 + ], + "p50_seconds": 0.0060125000309199095, + "p95_seconds": 0.006374125019647181, + "p99_seconds": 0.006374125019647181, + "maximum_seconds": 0.006374125019647181, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15380, + "Questions": 4 + }, + { + "Bytes_sent": 15380, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + }, + { + "Bytes_sent": 15381, + "Questions": 4 + } + ] + }, + "second10_save": { + "samples_seconds": [ + 0.01842504198430106, + 0.016915374959353358, + 0.01750191702740267, + 0.016256875009275973, + 0.01602291699964553 + ], + "p50_seconds": 0.016915374959353358, + "p95_seconds": 0.01842504198430106, + "p99_seconds": 0.01842504198430106, + "maximum_seconds": 0.01842504198430106, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12435, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + } + ] + }, + "filter20": { + "samples_seconds": [ + 0.02724245801800862, + 0.022826333006378263, + 0.03516616701381281, + 0.021462041011545807, + 0.023176041955593973 + ], + "p50_seconds": 0.023176041955593973, + "p95_seconds": 0.03516616701381281, + "p99_seconds": 0.03516616701381281, + "maximum_seconds": 0.03516616701381281, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 141272, + "Questions": 64 + }, + { + "Bytes_sent": 134733, + "Questions": 57 + }, + { + "Bytes_sent": 134734, + "Questions": 57 + }, + { + "Bytes_sent": 134734, + "Questions": 57 + }, + { + "Bytes_sent": 134734, + "Questions": 57 + } + ] + }, + "cell_save": { + "samples_seconds": [ + 0.007502541993744671, + 0.00725866702850908, + 0.018350000027567148, + 0.007054875022731721, + 0.007763291010633111 + ], + "p50_seconds": 0.007502541993744671, + "p95_seconds": 0.018350000027567148, + "p99_seconds": 0.018350000027567148, + "maximum_seconds": 0.018350000027567148, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4165, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + } + ] + }, + "filter_cell100": { + "samples_seconds": [ + 0.03877783298958093, + 0.03749154199613258, + 0.04011900001205504, + 0.038218542002141476, + 0.03963516699150205 + ], + "p50_seconds": 0.03877783298958093, + "p95_seconds": 0.04011900001205504, + "p99_seconds": 0.04011900001205504, + "maximum_seconds": 0.04011900001205504, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 168042, + "Questions": 57 + }, + { + "Bytes_sent": 168042, + "Questions": 57 + }, + { + "Bytes_sent": 168043, + "Questions": 57 + }, + { + "Bytes_sent": 168043, + "Questions": 57 + }, + { + "Bytes_sent": 168043, + "Questions": 57 + } + ] + }, + "filter_cell_and_epoch10": { + "samples_seconds": [ + 0.01800766703672707, + 0.018951375037431717, + 0.020278000039979815, + 0.018302250013221055, + 0.01821737503632903 + ], + "p50_seconds": 0.018302250013221055, + "p95_seconds": 0.020278000039979815, + "p99_seconds": 0.020278000039979815, + "maximum_seconds": 0.020278000039979815, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 125358, + "Questions": 58 + }, + { + "Bytes_sent": 125358, + "Questions": 58 + }, + { + "Bytes_sent": 125359, + "Questions": 58 + }, + { + "Bytes_sent": 125359, + "Questions": 58 + }, + { + "Bytes_sent": 125359, + "Questions": 58 + } + ] + }, + "remove_first10_revision_preflight": { + "samples_seconds": [ + 0.0059079170459881425, + 0.00627808301942423, + 0.006188458995893598, + 0.005992332997266203, + 0.007050833024550229 + ], + "p50_seconds": 0.006188458995893598, + "p95_seconds": 0.007050833024550229, + "p99_seconds": 0.007050833024550229, + "maximum_seconds": 0.007050833024550229, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15799, + "Questions": 4 + }, + { + "Bytes_sent": 15799, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + } + ] + }, + "remove_first10_save": { + "samples_seconds": [ + 0.016256083035841584, + 0.01609495800221339, + 0.016188249981496483, + 0.015846625028643757, + 0.018834499991498888 + ], + "p50_seconds": 0.016188249981496483, + "p95_seconds": 0.018834499991498888, + "p99_seconds": 0.018834499991498888, + "maximum_seconds": 0.018834499991498888, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12452, + "Questions": 29 + }, + { + "Bytes_sent": 12423, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + }, + { + "Bytes_sent": 12453, + "Questions": 29 + } + ] + }, + "filter_hierarchy_after_epoch_remove": { + "samples_seconds": [ + 0.011758790991734713, + 0.012778042000718415, + 0.012820375035516918, + 0.01242733298568055, + 0.011840666003990918 + ], + "p50_seconds": 0.01242733298568055, + "p95_seconds": 0.012820375035516918, + "p99_seconds": 0.012820375035516918, + "maximum_seconds": 0.012820375035516918, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112890, + "Questions": 55 + }, + { + "Bytes_sent": 112890, + "Questions": 55 + }, + { + "Bytes_sent": 112891, + "Questions": 55 + }, + { + "Bytes_sent": 112891, + "Questions": 55 + }, + { + "Bytes_sent": 112891, + "Questions": 55 + } + ] + }, + "filter_remaining10": { + "samples_seconds": [ + 0.0174046250176616, + 0.017987709026783705, + 0.01727400004165247, + 0.01689045800594613, + 0.017530124983750284 + ], + "p50_seconds": 0.0174046250176616, + "p95_seconds": 0.017987709026783705, + "p99_seconds": 0.017987709026783705, + "maximum_seconds": 0.017987709026783705, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 124593, + "Questions": 57 + }, + { + "Bytes_sent": 124593, + "Questions": 57 + }, + { + "Bytes_sent": 124594, + "Questions": 57 + }, + { + "Bytes_sent": 124594, + "Questions": 57 + }, + { + "Bytes_sent": 124594, + "Questions": 57 + } + ] + }, + "remove_second10_revision_preflight": { + "samples_seconds": [ + 0.005977375025395304, + 0.005894292029552162, + 0.006003624992445111, + 0.005952916049864143, + 0.006602292007301003 + ], + "p50_seconds": 0.005977375025395304, + "p95_seconds": 0.006602292007301003, + "p99_seconds": 0.006602292007301003, + "maximum_seconds": 0.006602292007301003, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15800, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + }, + { + "Bytes_sent": 15801, + "Questions": 4 + } + ] + }, + "remove_second10_save": { + "samples_seconds": [ + 0.016056958003900945, + 0.015534125035628676, + 0.015537166967988014, + 0.015851082978770137, + 0.01648387499153614 + ], + "p50_seconds": 0.015851082978770137, + "p95_seconds": 0.01648387499153614, + "p99_seconds": 0.01648387499153614, + "maximum_seconds": 0.01648387499153614, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12464, + "Questions": 29 + }, + { + "Bytes_sent": 12435, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + }, + { + "Bytes_sent": 12465, + "Questions": 29 + } + ] + }, + "filter_after_all_epoch_removals": { + "samples_seconds": [ + 0.011692999978549778, + 0.011391708976589143, + 0.011859584017656744, + 0.011452833947259933, + 0.012298792018555105 + ], + "p50_seconds": 0.011692999978549778, + "p95_seconds": 0.012298792018555105, + "p99_seconds": 0.012298792018555105, + "maximum_seconds": 0.012298792018555105, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + } + ] + }, + "remove_cell_save": { + "samples_seconds": [ + 0.0071121660294011235, + 0.007018374977633357, + 0.007366625010035932, + 0.007096500019542873, + 0.007313000038266182 + ], + "p50_seconds": 0.0071121660294011235, + "p95_seconds": 0.007366625010035932, + "p99_seconds": 0.007366625010035932, + "maximum_seconds": 0.007366625010035932, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 4167, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4165, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + }, + { + "Bytes_sent": 4168, + "Questions": 11 + } + ] + }, + "filter_after_cell_removal": { + "samples_seconds": [ + 0.011266125016845763, + 0.01227129198377952, + 0.013780042005237192, + 0.011646541010122746, + 0.011481249995995313 + ], + "p50_seconds": 0.011646541010122746, + "p95_seconds": 0.013780042005237192, + "p99_seconds": 0.013780042005237192, + "maximum_seconds": 0.013780042005237192, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 112133, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + }, + { + "Bytes_sent": 112134, + "Questions": 54 + } + ] + }, + "tag10_then10_filter20_http_total": { + "samples_seconds": [ + 0.09287745808251202, + 0.06778370792744681, + 0.08074883400695398, + 0.06833187508163974, + 0.06927029194775969 + ], + "p50_seconds": 0.06927029194775969, + "p95_seconds": 0.09287745808251202, + "p99_seconds": 0.09287745808251202, + "maximum_seconds": 0.09287745808251202, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "cell_tag_then_cell_filter_http_total": { + "samples_seconds": [ + 0.0462803749833256, + 0.04475020902464166, + 0.05846900003962219, + 0.0452734170248732, + 0.04739845800213516 + ], + "p50_seconds": 0.0462803749833256, + "p95_seconds": 0.05846900003962219, + "p99_seconds": 0.05846900003962219, + "maximum_seconds": 0.05846900003962219, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "first10_selected_action_http_total": { + "samples_seconds": [ + 0.04083583306055516, + 0.022465207963250577, + 0.021859166969079524, + 0.024600459029898047, + 0.024479250016156584 + ], + "p50_seconds": 0.024479250016156584, + "p95_seconds": 0.04083583306055516, + "p99_seconds": 0.04083583306055516, + "maximum_seconds": 0.04083583306055516, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "second10_selected_action_http_total": { + "samples_seconds": [ + 0.02479916700394824, + 0.02249216695781797, + 0.02372350002406165, + 0.022269375040195882, + 0.02161499997600913 + ], + "p50_seconds": 0.02249216695781797, + "p95_seconds": 0.02479916700394824, + "p99_seconds": 0.02479916700394824, + "maximum_seconds": 0.02479916700394824, + "quantile_method": "nearest_rank", + "sql_session_deltas": [] + }, + "autocomplete_cold_diagnostic": { + "samples_seconds": [ + 0.023283249989617616 + ], + "p50_seconds": 0.023283249989617616, + "p95_seconds": 0.023283249989617616, + "p99_seconds": 0.023283249989617616, + "maximum_seconds": 0.023283249989617616, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 215729, + "Questions": 91 + } + ] + }, + "autocomplete_warm_diagnostic": { + "samples_seconds": [ + 0.029437625024002045 + ], + "p50_seconds": 0.029437625024002045, + "p95_seconds": 0.029437625024002045, + "p99_seconds": 0.029437625024002045, + "maximum_seconds": 0.029437625024002045, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 215729, + "Questions": 91 + } + ] + }, + "autocomplete_empty_diagnostic": { + "samples_seconds": [ + 0.03325066698016599 + ], + "p50_seconds": 0.03325066698016599, + "p95_seconds": 0.03325066698016599, + "p99_seconds": 0.03325066698016599, + "maximum_seconds": 0.03325066698016599, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 218807, + "Questions": 91 + } + ] + }, + "same_server_native_reuse_filter20": { + "samples_seconds": [ + 0.020739166997373104 + ], + "p50_seconds": 0.020739166997373104, + "p95_seconds": 0.020739166997373104, + "p99_seconds": 0.020739166997373104, + "maximum_seconds": 0.020739166997373104, + "quantile_method": "nearest_rank", + "sql_session_deltas": [ + { + "Bytes_sent": 134735, + "Questions": 57 + } + ] + } + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 167 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "page_cells": true, + "target_specification": "tag10_then10_filter20_and_cell_epoch_hierarchy", + "baseline_harness_sha256": "272fe050c8762ed4ea45bd013e236e8723d8fe46f5e7e293c58e2edf1fd52ddc", + "mysql_version": "8.4.2", + "seed_seconds": 0.4073622500291094, + "seed_checkpoint_seconds": 0.18052658397937194, + "native_lookup_startup_preparation": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.054246 + } + }, + "project_uuid": "e9bffb2b-d4b9-42e6-add4-e9fef1532cf7", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.233545 + }, + "selected_epoch_uuids": { + "first10": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5" + ], + "second10": [ + "ad573668-6512-6e55-649e-cb23ae1d4888", + "16dc368a-89b4-28b2-4854-84313ba67a39", + "37834f2f-2576-2f23-e1f7-4a531cbe445d", + "454f63ac-30c8-3229-97ef-025edff6abd2", + "5ef6fdf3-2513-aa7c-d11f-72beccf132b9", + "1253e937-3e78-1b75-0026-6caa55150e08", + "482d9673-cfee-5de3-91f9-7fde4d1c84f9", + "3346f2bb-f6c3-4bd2-dbe2-8bd1bb657d0e", + "9537f32e-c759-9e1a-e953-af6c9f929fe7", + "0fd42b3f-73c4-48b3-4940-b339f87d07ad" + ], + "cell": "0604cd31-38fe-ed20-2ef2-93e062da2f47", + "cell_children": [ + "5feceb66-ffc8-6f38-d952-786c6d696c79", + "6b86b273-ff34-fce1-9d6b-804eff5a3f57", + "d4735e3a-265e-16ee-e03f-59718b9b5d03", + "4e074085-62be-db8b-60ce-05c1decfe3ad", + "4b227777-d4dd-1fc6-1c6f-884f48641d02", + "ef2d127d-e37b-942b-aad0-6145e54b0c61", + "e7f6c011-776e-8db7-cd33-0b54174fd76f", + "7902699b-e42c-8a8e-46fb-bb4501726517", + "2c624232-cdd2-2177-1294-dfbb310aca00", + "19581e27-de7c-ed00-ff1c-e50b2047e7a5", + "4a44dc15-3642-04a8-0fe8-0e9039455cc1", + "4fc82b26-aecb-47d2-868c-4efbe3581732", + "6b51d431-df5d-7f14-1cbe-ceccf79edf3d", + "3fdba35f-04dc-8c46-2986-c992bcf87554", + "8527a891-e224-1369-50ff-32ca212b45bc", + "e629fa65-98d7-3276-8f7c-726b4b621285", + "b17ef6d1-9c7a-5b1e-e83b-907c595526dc", + "4523540f-1504-cd17-100c-4835e85b7eef", + "4ec9599f-c203-d176-a301-536c2e091a19", + "9400f1b2-1cb5-27d7-fa3d-3eabba93557a", + "f5ca38f7-48a1-d6ea-f726-b8a42fb575c3", + "6f4b6612-125f-b3a0-daec-d2799dfd6c9c", + "785f3ec7-eb32-f30b-90cd-0fcf3657d388", + "535fa30d-7e25-dd8a-49f1-536779734ec8", + "c2356069-e9d1-e79c-a924-378153cfbbfb", + "b7a56873-cd77-1f2c-446d-369b649430b6", + "5f9c4ab0-8cac-7457-e911-1a30e4664920", + "670671cd-9740-4156-226e-507973f2ab83", + "59e19706-d51d-39f6-6711-c2653cd7eb12", + "35135aaa-6cc2-3891-b40c-b3f378c53a17", + "624b60c5-8c9d-8bfb-6ff1-886c2fd605d2", + "eb1e33e8-a81b-697b-7585-5af6bfcdbcbf", + "e29c9c18-0c62-79b0-b02a-bd6a1801c7c0", + "c6f3ac57-944a-5314-90cd-39902d0f7777", + "86e50149-6586-6131-2a9e-0b35558d84f6", + "9f14025a-f006-5b30-e47e-23ebb3b491d3", + "76a50887-d8f1-c2e9-3017-55428990ad81", + "7a61b537-01be-fdae-0eee-ffaecc73f14e", + "aea92132-c4cb-eb26-3e6a-c2bf6c183b5d", + "0b918943-df09-62bc-7a18-24c0555a3893", + "d59eced1-ded0-7f84-c145-592f65bdf854", + "3d914f93-48c9-cc0f-f8a7-9716700b9fcd", + "73475cb4-0a56-8e8d-a8a0-45ced110137e", + "44cb730c-4204-80a0-477b-505ae68af508", + "71ee45a3-c0db-9a98-65f7-313dd3372cf6", + "811786ad-1ae7-4adf-dd20-dd0372abaaeb", + "25fc0e70-96fc-6537-1820-2dc30b0c580b", + "31489056-e091-6d59-fe3a-dd79e63f095a", + "98010bd9-270f-9b10-0b62-14a21754fd33", + "0e17daca-5f3e-175f-448b-acace3bc0da4", + "1a656259-0ef1-9d10-45d0-6c4055742d38", + "031b4af5-197e-c30a-926f-48cf40e11a7d", + "41cfc0d1-f2d1-27b0-4555-b7246d84019b", + "2858dcd1-057d-3eae-7f7d-5f782167e24b", + "2fca346d-b656-1871-02ce-806ac732e06a", + "02d20bbd-7e39-4ad5-999a-4cebabac9619", + "7688b6ef-5255-5962-d008-fff894223582", + "c837649c-ce43-f272-9138-e72cc3152070", + "6208ef0f-7750-c111-548c-f90b6ea1d0d0", + "3e1e967e-9b79-3e90-8f8e-ae83c74dba9b", + "39fa9ec1-90ee-e7b6-f4df-f1100d6343e1", + "d029fa3a-95e1-74a1-9934-857f535eb942", + "81b8a03f-97e8-787c-53fe-1a86bda042b6", + "da4ea2a5-506f-2693-eae1-90d9360a1f31", + "a68b412c-4282-555f-1554-6cf6e1fc4289", + "108c995b-953c-8a35-5611-03e2014cf828", + "3ada92f2-8b4c-eda3-8562-ebf047c6ff05", + "49d180ec-f561-3281-9571-bf39d9b7b342", + "a21855da-08cb-102d-1d21-7c53dc5824a3", + "c75cb66a-e28d-8ebc-6ede-d002c28a8ba0", + "ff5a1ae0-12af-a5d4-c889-c50ad427aaf5", + "7f2253d7-e228-b22a-08bd-a1f09c516f6f", + "87226162-0421-7edd-b39e-7df969e0698a", + "96061e92-f58e-4bdc-dee7-3df36183fe3a", + "eb624dbe-56eb-6620-ae62-080c10a273ca", + "f369cb89-fc62-7e66-8987-007d121ed1ea", + "f74efabe-f12e-a619-e30b-79bddef89cff", + "a88a7902-cb4e-f697-ba0b-6759c50e8c10", + "349c4120-1b62-db85-1192-665c504b350f", + "98a3ab7c-340e-8a03-3e7b-37b6ef942875", + "48449a14-a4ff-7d79-bb7a-1b6f3d488eba", + "5316ca1c-5ddc-a8e6-cecc-fce58f3b8540", + "a46e3763-2fa6-ca51-a13f-e39a567b3c23", + "bbb965ab-0c80-d653-8cf2-184babad2a56", + "44c8031c-b036-a735-0d8b-9b8603af662a", + "b4944c6f-f08d-c6f4-3da2-e9c824669b7d", + "434c9b5a-e514-646b-bd91-b50032ca579e", + "bdd2d3af-3a5a-1213-497d-4f1f7bfcda89", + "8b940be7-fb78-aaa6-b656-7dd7a3987996", + "cd70bea0-23f7-52a0-564a-bb6ed08d42c1", + "69f59c27-3b6e-669a-c32a-6dd5e1b2cb63", + "1da51b8d-8ff9-8f6a-48f8-0ae79fe3ca6c", + "82416496-09f8-8ccd-2a0a-5b233a07a538", + "6e400187-1c0c-f27c-7634-ef1dc478408f", + "e3d6c4d4-599e-0088-2384-ca981ee287ed", + "ad48ff99-415b-2f00-7dc3-5b7eb553fd1e", + "7b1a278f-5abe-8e9d-a907-fc9c29dfd432", + "d6d824ab-ba4a-fde8-1129-c71dea75b810", + "29db0c67-82db-d500-0559-ef4d9e953e30", + "8c1f1046-219d-dd21-6a02-3f792356ddf1" + ] + }, + "backup_receipts": [ + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 1, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 2, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 3, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 4, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 5, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 6, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 7, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 8, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 9, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 10, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 11, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 12, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 13, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 14, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 15, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 16, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 17, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 18, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 19, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 20, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 21, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 22, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 23, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 24, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 25, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 26, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 27, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_first10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 28, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_second10_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 29, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "remove_cell_save", + "persistence": { + "backup": { + "completed_sequence": 0, + "last_error": null, + "last_success": null, + "pending": true, + "requested_sequence": 30, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_first10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:17:24.169576+00:00", + "pending": true, + "requested_sequence": 31, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_second10_save", + "persistence": { + "backup": { + "completed_sequence": 30, + "last_error": null, + "last_success": "2026-09-30T15:17:24.169576+00:00", + "pending": true, + "requested_sequence": 32, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_first10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:17:24.486314+00:00", + "pending": true, + "requested_sequence": 33, + "running": false, + "status": "pending" + }, + "database": "committed" + } + }, + { + "operation": "profile_remove_second10", + "persistence": { + "backup": { + "completed_sequence": 32, + "last_error": null, + "last_success": "2026-09-30T15:17:24.486314+00:00", + "pending": true, + "requested_sequence": 34, + "running": false, + "status": "pending" + }, + "database": "committed" + } + } + ], + "preparation_index_seconds": 0, + "lookup_mode": "persistent_native_sql_no_post_seed_tag_cache_preparation", + "bundle_definitions": { + "tag10_then10_filter20_http_total": [ + "first10_revision_preflight", + "first10_save", + "second10_revision_preflight", + "second10_save", + "filter20" + ], + "cell_tag_then_cell_filter_http_total": [ + "cell_save", + "filter_cell100" + ], + "first10_selected_action_http_total": [ + "first10_revision_preflight", + "first10_save" + ], + "second10_selected_action_http_total": [ + "second10_revision_preflight", + "second10_save" + ] + }, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:17:25.252632+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 0.0019153340253978968 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.0005384999676607549 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.0007603340200148523 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0002502499846741557 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 0.0018970409873872995 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.00045908300671726465 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.0006526659708470106 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00018674996681511402 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 0.001917750050779432 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.005181541957426816 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.005963417002931237 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0002708330284804106 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "38", + "ref": "const", + "rows": 3787, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 9769, + "filtered": 100.0, + "Extra": "Using where; Using index for group-by (scanning)" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "index", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 7575, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 9, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "filter20_cpu_profile": { + "top_functions": [ + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 331, + "function": "", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.833000000000001e-06, + "cumulative_seconds": 0.055883583 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 159, + "function": "request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.125e-06, + "cumulative_seconds": 0.055855125000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1163, + "function": "get", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.916000000000001e-06, + "cumulative_seconds": 0.055037958000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/testing.py", + "line": 204, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.5292000000000002e-05, + "cumulative_seconds": 0.055032042 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1062, + "function": "open", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.916e-06, + "cumulative_seconds": 0.054734000000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 984, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0544000000000001e-05, + "cumulative_seconds": 0.054719959000000006 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/test.py", + "line": 1230, + "function": "run_wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.206e-06, + "cumulative_seconds": 0.054527291000000006 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1529, + "function": "__call__", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.25e-06, + "cumulative_seconds": 0.054501125000000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 1479, + "function": "wsgi_app", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0334000000000001e-05, + "cumulative_seconds": 0.054494875000000005 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 904, + "function": "full_dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 7.959000000000001e-06, + "cumulative_seconds": 0.05426191700000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/app.py", + "line": 879, + "function": "dispatch_request", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.316600000000001e-05, + "cumulative_seconds": 0.05404975 + }, + { + "file": "python/workspace_api.py", + "line": 716, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.011800000000001e-05, + "cumulative_seconds": 0.053952625000000004 + }, + { + "file": "python/workspace_annotations.py", + "line": 295, + "function": "for_epochs", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 0.000110742, + "cumulative_seconds": 0.021559708 + }, + { + "file": "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py", + "line": 322, + "function": "traced_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00020169600000000002, + "cumulative_seconds": 0.021302794 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 412, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 9.6835e-05, + "cumulative_seconds": 0.020735294 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/connection.py", + "line": 402, + "function": "_execute_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000112442, + "cumulative_seconds": 0.020493535 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 27, + "calls": 38, + "self_seconds": 2.8749000000000002e-05, + "cumulative_seconds": 0.020399084 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 249, + "function": "native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.0751000000000001e-05, + "cumulative_seconds": 0.020334834 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 150, + "function": "execute", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.8716000000000005e-05, + "cumulative_seconds": 0.020121799000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/cursors.py", + "line": 332, + "function": "_query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 6.766500000000001e-05, + "cumulative_seconds": 0.019671499000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 575, + "function": "query", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.2996e-05, + "cumulative_seconds": 0.019196248000000003 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 851, + "function": "_read_query_result", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.2428e-05, + "cumulative_seconds": 0.018222878 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1288, + "function": "read", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 7.029700000000001e-05, + "cumulative_seconds": 0.018144459 + }, + { + "file": "python/workspace_state_generation.py", + "line": 101, + "function": "_rows", + "primitive_calls": 46, + "calls": 46, + "self_seconds": 5.5586000000000006e-05, + "cumulative_seconds": 0.016481585 + }, + { + "file": "python/workspace_state_generation.py", + "line": 197, + "function": "response_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.6333e-05, + "cumulative_seconds": 0.016095541 + }, + { + "file": "python/workspace_state_generation.py", + "line": 233, + "function": "_attest_contract", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 6.5583e-05, + "cumulative_seconds": 0.016065292000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 128, + "function": "deepcopy", + "primitive_calls": 78, + "calls": 17170, + "self_seconds": 0.009397953, + "cumulative_seconds": 0.016016376000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 201, + "function": "_deepcopy_list", + "primitive_calls": 62, + "calls": 102, + "self_seconds": 0.000313937, + "cumulative_seconds": 0.015887622 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/copy.py", + "line": 227, + "function": "_deepcopy_dict", + "primitive_calls": 1242, + "calls": 1284, + "self_seconds": 0.002823383, + "cumulative_seconds": 0.013861159000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 763, + "function": "_read_packet", + "primitive_calls": 765, + "calls": 765, + "self_seconds": 0.001183477, + "cumulative_seconds": 0.013647774000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 813, + "function": "_read_bytes", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.00055718, + "cumulative_seconds": 0.010595909 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 132, + "function": "__enter__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 2.4160000000000002e-06, + "cumulative_seconds": 0.01029525 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/contextlib.py", + "line": 141, + "function": "__exit__", + "primitive_calls": 1, + "calls": 4, + "self_seconds": 5.961e-06, + "cumulative_seconds": 0.010047500000000001 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 1530, + "calls": 1530, + "self_seconds": 0.000202833, + "cumulative_seconds": 0.009966704 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/socket.py", + "line": 704, + "function": "readinto", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 7.1325e-05, + "cumulative_seconds": 0.009763871 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1299, + "function": "recv_into", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 7.6537e-05, + "cumulative_seconds": 0.00965621 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/ssl.py", + "line": 1157, + "function": "read", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 4.4206e-05, + "cumulative_seconds": 0.009569875 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 67, + "calls": 67, + "self_seconds": 0.009520961000000001, + "cumulative_seconds": 0.009520961000000001 + }, + { + "file": "python/workspace_state_generation.py", + "line": 134, + "function": "_active_ddl_guard", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 3.4702e-05, + "cumulative_seconds": 0.009518833 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1370, + "function": "_read_result_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 5.7791e-05, + "cumulative_seconds": 0.008029705 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/__init__.py", + "line": 138, + "function": "jsonify", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 9.917e-06, + "cumulative_seconds": 0.007209750000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 189, + "function": "response", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.0667e-05, + "cumulative_seconds": 0.0071941670000000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 869, + "function": "to_dicts", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 2.0088e-05, + "cumulative_seconds": 0.007106127 + }, + { + "file": "python/workspace_api.py", + "line": 61, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 3.9334e-05, + "cumulative_seconds": 0.007095667000000001 + }, + { + "file": "python/workspace_api.py", + "line": 62, + "function": "browser_safe", + "primitive_calls": 1, + "calls": 9641, + "self_seconds": 0.003128445, + "cumulative_seconds": 0.005557 + }, + { + "file": "python/workspace_api.py", + "line": 66, + "function": "", + "primitive_calls": 1, + "calls": 1363, + "self_seconds": 0.001356685, + "cumulative_seconds": 0.0055550420000000005 + }, + { + "file": "python/workspace_api.py", + "line": 68, + "function": "", + "primitive_calls": 2, + "calls": 102, + "self_seconds": 0.000207931, + "cumulative_seconds": 0.005543167000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1416, + "function": "_read_rowdata_packet", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.000348339, + "cumulative_seconds": 0.005187870000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 1231, + "function": "cursor", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 1.4085000000000002e-05, + "cumulative_seconds": 0.004998834000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 173, + "function": "_rows", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.2874e-05, + "cumulative_seconds": 0.004452666 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 268, + "function": "_native_read", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.8374000000000003e-05, + "cumulative_seconds": 0.00418375 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 311, + "function": "native_context", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 3.9625e-05, + "cumulative_seconds": 0.0041300420000000004 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1429, + "function": "_read_row_from_packet", + "primitive_calls": 428, + "calls": 428, + "self_seconds": 0.000943448, + "cumulative_seconds": 0.00309484 + }, + { + "file": "python/workspace_state_generation.py", + "line": 125, + "function": "_observer_status", + "primitive_calls": 8, + "calls": 8, + "self_seconds": 3.0752e-05, + "cumulative_seconds": 0.002996167 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 1448, + "function": "_get_descriptions", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00031073, + "cumulative_seconds": 0.0027641270000000003 + }, + { + "file": "python/workspace_state_generation.py", + "line": 115, + "function": "_triggers", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.0840000000000001e-06, + "cumulative_seconds": 0.00249225 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 163, + "function": "read_length_coded_string", + "primitive_calls": 2712, + "calls": 2712, + "self_seconds": 0.0008386870000000001, + "cumulative_seconds": 0.002463757 + }, + { + "file": "python/workspace_state_generation.py", + "line": 107, + "function": "_ddl", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 2.6045000000000002e-05, + "cumulative_seconds": 0.002096749 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 898, + "function": "", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 5.2901e-05, + "cumulative_seconds": 0.002083417 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 185, + "function": "_metadata", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.8873e-05, + "cumulative_seconds": 0.001887292 + }, + { + "file": "python/workspace_annotations.py", + "line": 195, + "function": "_chips", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 3.8842000000000005e-05, + "cumulative_seconds": 0.0018064630000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 899, + "function": "", + "primitive_calls": 86, + "calls": 86, + "self_seconds": 0.00036378800000000003, + "cumulative_seconds": 0.0017890520000000002 + }, + { + "file": "python/workspace_protocol_state.py", + "line": 101, + "function": "selected", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.0127000000000001e-05, + "cumulative_seconds": 0.0017238330000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 183, + "function": "dumps", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.5582e-05, + "cumulative_seconds": 0.0017133740000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 183, + "function": "encode", + "primitive_calls": 11, + "calls": 11, + "self_seconds": 2.1001e-05, + "cumulative_seconds": 0.0016796250000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 188, + "function": "_validated_tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.0735e-05, + "cumulative_seconds": 0.0016687540000000002 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/encoder.py", + "line": 205, + "function": "iterencode", + "primitive_calls": 9, + "calls": 9, + "self_seconds": 0.001655624, + "cumulative_seconds": 0.001655624 + }, + { + "file": "python/workspace_curation.py", + "line": 170, + "function": "_rows", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 6.041e-06, + "cumulative_seconds": 0.0016269580000000002 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 37540, + "calls": 37540, + "self_seconds": 0.001579066, + "cumulative_seconds": 0.001579066 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 232, + "function": "__init__", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 8.209100000000001e-05, + "cumulative_seconds": 0.0015381350000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 166, + "function": "dumps", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 4.5840000000000005e-06, + "cumulative_seconds": 0.001499333 + }, + { + "file": "python/workspace_service.py", + "line": 748, + "function": "epoch_page", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.0418e-05, + "cumulative_seconds": 0.001481625 + }, + { + "file": "python/workspace_service.py", + "line": 778, + "function": "_epoch_page_identities", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 5.3036000000000005e-05, + "cumulative_seconds": 0.0014375000000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 236, + "function": "_parse_field_descriptor", + "primitive_calls": 169, + "calls": 169, + "self_seconds": 0.000321222, + "cumulative_seconds": 0.001434004 + }, + { + "file": "python/workspace_state_generation.py", + "line": 347, + "function": "token", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 1.1835000000000001e-05, + "cumulative_seconds": 0.001308874 + }, + { + "file": "python/workspace_state_generation.py", + "line": 359, + "function": "_fresh_token", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 1.9957000000000002e-05, + "cumulative_seconds": 0.001283249 + }, + { + "file": "python/workspace_state_generation.py", + "line": 311, + "function": "_scope", + "primitive_calls": 4, + "calls": 4, + "self_seconds": 1.0588000000000001e-05, + "cumulative_seconds": 0.0012372090000000002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 282, + "function": "__and__", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 1.0955000000000001e-05, + "cumulative_seconds": 0.001231415 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/expression.py", + "line": 178, + "function": "restrict", + "primitive_calls": 14, + "calls": 14, + "self_seconds": 8.0241e-05, + "cumulative_seconds": 0.00122046 + }, + { + "file": "python/workspace_explorer.py", + "line": 60, + "function": "protocol_binding_header", + "primitive_calls": 3, + "calls": 3, + "self_seconds": 1.0375000000000001e-05, + "cumulative_seconds": 0.001140292 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 223, + "function": "attributes", + "primitive_calls": 1006, + "calls": 1006, + "self_seconds": 0.000370603, + "cumulative_seconds": 0.001131045 + }, + { + "file": "python/workspace_annotations.py", + "line": 34, + "function": "text", + "primitive_calls": 416, + "calls": 416, + "self_seconds": 0.000344121, + "cumulative_seconds": 0.001093559 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/__init__.py", + "line": 299, + "function": "loads", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 5.7661e-05, + "cumulative_seconds": 0.0010433340000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/protocol.py", + "line": 61, + "function": "read", + "primitive_calls": 2712, + "calls": 2712, + "self_seconds": 0.000883326, + "cumulative_seconds": 0.001001099 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 22, + "calls": 78, + "self_seconds": 5.9162e-05, + "cumulative_seconds": 0.0009938730000000002 + }, + { + "file": "python/workspace_annotations.py", + "line": 40, + "function": "tags", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 6.4268e-05, + "cumulative_seconds": 0.000976505 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 20369, + "calls": 20369, + "self_seconds": 0.000925852, + "cumulative_seconds": 0.000956848 + }, + { + "file": "python/workspace_service.py", + "line": 236, + "function": "source_scope", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 2.9469000000000002e-05, + "cumulative_seconds": 0.000953541 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/heading.py", + "line": 285, + "function": "__getitem__", + "primitive_calls": 745, + "calls": 745, + "self_seconds": 0.000133812, + "cumulative_seconds": 0.0009465220000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/decoder.py", + "line": 332, + "function": "decode", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 8.2749e-05, + "cumulative_seconds": 0.0009448740000000001 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/datajoint/condition.py", + "line": 278, + "function": "make_condition", + "primitive_calls": 14, + "calls": 56, + "self_seconds": 0.000252074, + "cumulative_seconds": 0.00090821 + }, + { + "file": "python/workspace_annotations.py", + "line": 42, + "function": "", + "primitive_calls": 66, + "calls": 66, + "self_seconds": 5.4155000000000006e-05, + "cumulative_seconds": 0.000898625 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/pymysql/connections.py", + "line": 869, + "function": "_execute_command", + "primitive_calls": 56, + "calls": 56, + "self_seconds": 0.00017737200000000002, + "cumulative_seconds": 0.0008883750000000001 + }, + { + "file": "python/workspace_annotations.py", + "line": 261, + "function": "filter_epoch_ids", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 8.886e-05, + "cumulative_seconds": 0.0008803330000000001 + }, + { + "file": "python/workspace_datastores.py", + "line": 192, + "function": "source_states", + "primitive_calls": 2, + "calls": 2, + "self_seconds": 7.208e-06, + "cumulative_seconds": 0.0008665830000000001 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 456, + "calls": 456, + "self_seconds": 0.000230088, + "cumulative_seconds": 0.0008293720000000001 + }, + { + "file": "/Users/maxwellsdm/.local/share/uv/python/cpython-3.11.13-macos-aarch64-none/lib/python3.11/json/decoder.py", + "line": 343, + "function": "raw_decode", + "primitive_calls": 89, + "calls": 89, + "self_seconds": 0.000817002, + "cumulative_seconds": 0.000817002 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/werkzeug/wrappers/response.py", + "line": 601, + "function": "get_json", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 2.9590000000000004e-06, + "cumulative_seconds": 0.000812959 + }, + { + "file": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI/.rieke-runtime/venv/lib/python3.11/site-packages/flask/json/provider.py", + "line": 181, + "function": "loads", + "primitive_calls": 1, + "calls": 1, + "self_seconds": 1.5830000000000001e-06, + "cumulative_seconds": 0.00079675 + }, + { + "file": "~", + "line": 0, + "function": "", + "primitive_calls": 20016, + "calls": 20016, + "self_seconds": 0.000750718, + "cumulative_seconds": 0.000750718 + } + ], + "native_sql_calls": [ + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0007289999630302191 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00034683296689763665 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00028316699899733067 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0003928749938495457 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00027595803840085864 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003370419726707041 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.0003447500057518482 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.0001521250233054161 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00021983298938721418 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00019200000679120421 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0005740419728681445 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0012521659955382347 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003592920256778598 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.00018645799718797207 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0003763329586945474 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002121249563060701 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00033579202136024833 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00029208301566541195 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00018783297855407 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.00022912502754479647 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004045419627800584 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.000322542036883533 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00017604196909815073 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00023958302335813642 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0003084169584326446 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.00023937498917803168 + }, + { + "thread": "filter", + "sql_shape": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "seconds": 0.00037987501127645373 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`epoch_uuid`,`included`,`tags`,`review_state`,`revision`,`metadata_fingerprint` FROM `recording_workspace`.`curation` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))AND( ( (`epoch_uuid`='?') OR (", + "seconds": 0.0007103749667294323 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`dataset_uuid`,`created_at`,`artifact_sha256` FROM `recording_workspace`.`dataset_revision` WHERE ( (`project_uuid`='?'))", + "seconds": 0.0002502910210750997 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.001726499991491437 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`target_kind`,`target_uuid`,`profile_uuid`,`tags`,`author_name`,`revision`,`updated_at` FROM `recording_workspace`.`shared_annotation` WHERE ( (`project_uuid`='?'))AND( (`target_kind`='?'))AND( ( (`target_uuid`='?') OR", + "seconds": 0.000497999950312078 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.00047483399976044893 + }, + { + "thread": "filter", + "sql_shape": "SELECT scope_epoch,generation FROM `recording_workspace`.`app_state_generation` WHERE project_uuid=%s AND scope_kind=%s AND scope_uuid=%s", + "seconds": 0.0002162500168196857 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`protocol_uuid`,`revision_uuid`,`version`,`bound_at` FROM `recording_workspace`.`protocol_binding` WHERE ( (`project_uuid`='?')AND(`protocol_uuid`='?'))", + "seconds": 0.0002269999822601676 + }, + { + "thread": "filter", + "sql_shape": "SELECT `project_uuid`,`source_sha256`,`version`,`frozen`,`archived`,`query_excluded`,`updated_at`,`actor`,`actor_kind`,`server_actor`,`reason` FROM `recording_workspace`.`data_store_state` WHERE ( (`project_uuid`='?'))", + "seconds": 0.00030795898055657744 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004632920026779175 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.00035358400782570243 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.0002062080311588943 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0004330839728936553 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.00023366697132587433 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0004393329727463424 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00040429196087643504 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00015970796812325716 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.000274707970675081 + }, + { + "thread": "filter", + "sql_shape": "SELECT @@server_uuid AS server_uuid,@@version AS version,CONNECTION_ID() AS connection_id", + "seconds": 0.00019929197151213884 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,TABLE_ID FROM information_schema.INNODB_TABLES WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.000484999967738986 + }, + { + "thread": "filter", + "sql_shape": "SELECT TRIGGER_NAME,EVENT_MANIPULATION,EVENT_OBJECT_TABLE,ACTION_TIMING,ACTION_STATEMENT,CREATED FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=%s", + "seconds": 0.0012307920260354877 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003642079536803067 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_consumers WHERE NAME IN ('?','?','?')", + "seconds": 0.0001947919954545796 + }, + { + "thread": "filter", + "sql_shape": "SELECT NAME,ENABLED FROM performance_schema.setup_instruments WHERE NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.000389167049434036 + }, + { + "thread": "filter", + "sql_shape": "SELECT PROCESSLIST_ID,NAME,INSTRUMENTED FROM performance_schema.threads WHERE TYPE='?' AND PROCESSLIST_ID IS NOT NULL", + "seconds": 0.0002192090032622218 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003327500307932496 + }, + { + "thread": "filter", + "sql_shape": "SELECT EVENT_SCHEMA,EVENT_NAME FROM information_schema.EVENTS LIMIT 1", + "seconds": 0.00029916601488366723 + }, + { + "thread": "filter", + "sql_shape": "SELECT CHANNEL_NAME FROM performance_schema.replication_applier_configuration LIMIT 1", + "seconds": 0.00014970795018598437 + }, + { + "thread": "filter", + "sql_shape": "SELECT THREAD_ID,EVENT_NAME FROM performance_schema.events_statements_current WHERE EVENT_NAME IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) AND END_EVENT_ID IS NULL LIMIT 1", + "seconds": 0.0002160840085707605 + }, + { + "thread": "filter", + "sql_shape": "SHOW GLOBAL STATUS WHERE Variable_name IN ('?','?','?','?','?','?','?','?','?','?','?','?','?','?')", + "seconds": 0.0003625000244937837 + } + ], + "limits": "Separate instrumented filter; background mirror flushed before profile. CPU cumulative times overlap." + }, + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.019975 + } + }, + "project_uuid": "e9bffb2b-d4b9-42e6-add4-e9fef1532cf7", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.088638 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.01782 + } + }, + "project_uuid": "e9bffb2b-d4b9-42e6-add4-e9fef1532cf7", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.131056 + }, + "seconds": 0.21972979203565046, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "workflow_peak_rss_before_durable_oracle_bytes": 170164224, + "durable_snapshot_verify_seconds": 0.03063724999083206, + "loaded_product_modules": { + "workspace_tree": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tree.py", + "workspace_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_predicates.py", + "workspace_cache_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_cache_lifecycle.py", + "workspace_metadata_objects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_metadata_objects.py", + "workspace_disk_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_disk_index.py", + "workspace_catalog_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_catalog_identity.py", + "recording_workspace": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/recording_workspace.py", + "workspace_recipes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_recipes.py", + "workspace_tree_code": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tree_code.py", + "workspace_service": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_service.py", + "workspace_tree_pages": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tree_pages.py", + "workspace_projects": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_projects.py", + "workspace_mysql_profile": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_mysql_profile.py", + "workspace_native_mysql": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_native_mysql.py", + "workspace_mysql_runtime": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_mysql_runtime.py", + "workspace_storage": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_storage.py", + "workspace_diff": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_diff.py", + "workspace_protocol_identity": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_protocol_identity.py", + "workspace_import_check": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_import_check.py", + "workspace_audit": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_audit.py", + "workspace_api": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_api.py", + "workspace_state_snapshot": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_state_snapshot.py", + "workspace_author_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_author_preferences.py", + "workspace_curation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_curation.py", + "workspace_annotations": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_annotations.py", + "workspace_shared_tag_index": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_shared_tag_index.py", + "workspace_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_paths.py", + "workspace_desktop_paths": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_desktop_paths.py", + "workspace_startup_registry": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_startup_registry.py", + "workspace_explorer": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_explorer.py", + "workspace_datastores": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_datastores.py", + "workspace_suggestions": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_suggestions.py", + "workspace_tag_predicates": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tag_predicates.py", + "workspace_export_folder": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_export_folder.py", + "workspace_import_progress": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_import_progress.py", + "workspace_project_preferences": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_project_preferences.py", + "workspace_protocol_state": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_protocol_state.py", + "workspace_state_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_state_generation.py", + "workspace_project_servers": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_project_servers.py", + "workspace_launcher": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_launcher.py", + "workspace_app_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_app_routes.py", + "workspace_folder_browser": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_folder_browser.py", + "workspace_h5_inbox": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_h5_inbox.py", + "workspace_tag_exchange": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_tag_exchange.py", + "workspace_external_tags": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_external_tags.py", + "workspace_qc": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_qc.py", + "workspace_search": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_search.py", + "workspace_matlab_masks": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_matlab_masks.py", + "workspace_matlab_routes": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_matlab_routes.py", + "workspace_mask_refresh": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_mask_refresh.py", + "workspace_matching_epochs": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_matching_epochs.py", + "workspace_candidate_exports": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_candidate_exports.py", + "workspace_backup_scheduler": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_backup_scheduler.py", + "workspace_recovery_store": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_recovery_store.py", + "workspace_recovery_generation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_recovery_generation.py", + "workspace_annotation_preparation": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_annotation_preparation.py", + "workspace_native_tag_lookup": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_native_tag_lookup.py", + "workspace_lifecycle": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_lifecycle.py", + "workspace_native_tag_filter": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-7porgom9/python/workspace_native_tag_filter.py" + }, + "owned_native_runtime_stopped": true, + "source_inventory_after": { + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "ad7adbf587069f60d06779def9f5f6b5e2848a6d43750daaee587c8fdaa1aa9f", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "17c37104693d46b416064ab05027c54added8d26ddd2ba6b7de202911ce5d592", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3f4b346a59e1b78aeea51b1d1c2812582eed009b4cb2cc36831830e0d62601ca", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "0ddf442ffefd00e16441868e89d5785ee4b302ffbb39ed6d0f17c9825d70c3ab", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "66a6a04c107053b3c0492e5ccd2e6f6e10b8479c107c0b58d5b5fd712800312c", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "a43e66ff47aaec64d0a862277b7751901775ab7f193f58c0106437b9fab1331b", + "python/workspace_native_tag_lookup.py": "d549e8084af074ab484759a2851fdacde7e632c334f55e2d65caee368e04ffd5", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "1917ae5b36553048027a19e1b68f99677a754dae1501d1e52be1cd3faaa2b4a5", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a" + }, + "source_unchanged": true, + "harness_unchanged": true, + "seconds": 9.253306082973722, + "finished_at": "2026-09-30T15:17:25.584669+00:00", + "peak_rss_bytes": 170164224, + "passed": true +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-results.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-results.json new file mode 100644 index 0000000..d854ec4 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-results.json @@ -0,0 +1,888 @@ +{ + "scope": "Native SQL lookup versus prior SQLite tag cache, same scientist workflow. Disposable native database, synthetic acquisition metadata, HTTP test-client timings.", + "passed": true, + "source_and_harness_unchanged_across_both_native_runs": true, + "samples_per_workflow_operation": 5, + "snapshot_manifest": "native-tag-source-pre-dictionary-snapshot.json", + "native_harness_sha256": "468173271c08020e7e1a7ce8b0fcdfc59693be0f9e3699a8caec342b2e77affd", + "scales": { + "500": { + "native_receipt": "native-tag-sequence-pre-dictionary-500.json", + "prior_receipt": "tag-sequence-after-500.json", + "comparison_ms": { + "first10_save": { + "prior_p50": 15.186292002908885, + "native_p50": 17.74270902387798, + "native_first_sample": 33.97225000662729, + "native_maximum": 33.97225000662729 + }, + "second10_save": { + "prior_p50": 13.435167027637362, + "native_p50": 16.915374959353358, + "native_first_sample": 18.42504198430106, + "native_maximum": 18.42504198430106 + }, + "filter20": { + "prior_p50": 31.089458032511175, + "native_p50": 23.176041955593973, + "native_first_sample": 27.24245801800862, + "native_maximum": 35.16616701381281 + }, + "tag10_then10_filter20_http_total": { + "prior_p50": 73.59912293031812, + "native_p50": 69.27029194775969, + "native_first_sample": 92.87745808251202, + "native_maximum": 92.87745808251202 + }, + "cell_save": { + "prior_p50": 6.7298339563421905, + "native_p50": 7.502541993744671, + "native_first_sample": 7.502541993744671, + "native_maximum": 18.350000027567148 + }, + "filter_cell100": { + "prior_p50": 41.47870797896758, + "native_p50": 38.77783298958093, + "native_first_sample": 38.77783298958093, + "native_maximum": 40.11900001205504 + }, + "filter_cell_and_epoch10": { + "prior_p50": 17.395791015587747, + "native_p50": 18.302250013221055, + "native_first_sample": 18.00766703672707, + "native_maximum": 20.278000039979815 + }, + "cell_tag_then_cell_filter_http_total": { + "prior_p50": 48.06662496412173, + "native_p50": 46.2803749833256, + "native_first_sample": 46.2803749833256, + "native_maximum": 58.46900003962219 + } + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 167 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "38", + "ref": "const", + "rows": 3787, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 542, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 9769, + "filtered": 100.0, + "Extra": "Using where; Using index for group-by (scanning)" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "index", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 7575, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 9, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 0.0019153340253978968 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.0005384999676607549 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.0007603340200148523 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0002502499846741557 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 0.0018970409873872995 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.00045908300671726465 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.0006526659708470106 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00018674996681511402 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 0.001917750050779432 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.005181541957426816 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.005963417002931237 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0002708330284804106 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_diagnostic_ms": { + "autocomplete_cold_diagnostic": 23.283249989617616, + "autocomplete_warm_diagnostic": 29.437625024002045, + "autocomplete_empty_diagnostic": 33.25066698016599 + }, + "initial_native_setup": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.054246 + } + }, + "project_uuid": "e9bffb2b-d4b9-42e6-add4-e9fef1532cf7", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.233545 + }, + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.019975 + } + }, + "project_uuid": "e9bffb2b-d4b9-42e6-add4-e9fef1532cf7", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.088638 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.01782 + } + }, + "project_uuid": "e9bffb2b-d4b9-42e6-add4-e9fef1532cf7", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.131056 + }, + "seconds": 0.21972979203565046, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "same_server_native_reuse_filter_ms": 20.739166997373104, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:17:25.252632+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "mysql_version": "8.4.2", + "runtime_seconds": 9.253306082973722, + "seed_seconds": 0.4073622500291094, + "seed_checkpoint_seconds": 0.18052658397937194, + "owned_native_runtime_stopped": true + }, + "100000": { + "native_receipt": "native-tag-sequence-pre-dictionary-100000.json", + "prior_receipt": "tag-sequence-after-100000.json", + "comparison_ms": { + "first10_save": { + "prior_p50": 17.622290994040668, + "native_p50": 24.99641600297764, + "native_first_sample": 56.14608299219981, + "native_maximum": 56.14608299219981 + }, + "second10_save": { + "prior_p50": 16.18437498109415, + "native_p50": 23.883083020336926, + "native_first_sample": 23.883083020336926, + "native_maximum": 26.714917039498687 + }, + "filter20": { + "prior_p50": 119.21920796157792, + "native_p50": 126.01441703736782, + "native_first_sample": 227.16829099226743, + "native_maximum": 227.16829099226743 + }, + "tag10_then10_filter20_http_total": { + "prior_p50": 165.9542090492323, + "native_p50": 202.98049901612103, + "native_first_sample": 327.71416497416794, + "native_maximum": 327.71416497416794 + }, + "cell_save": { + "prior_p50": 7.809958013240248, + "native_p50": 8.758000039961189, + "native_first_sample": 10.468583030160517, + "native_maximum": 10.496834001969546 + }, + "filter_cell100": { + "prior_p50": 129.82887495309114, + "native_p50": 160.0392499822192, + "native_first_sample": 154.43866699934006, + "native_maximum": 163.26100000878796 + }, + "filter_cell_and_epoch10": { + "prior_p50": 106.19708400918171, + "native_p50": 124.78045799070969, + "native_first_sample": 123.39312495896593, + "native_maximum": 136.43654203042388 + }, + "cell_tag_then_cell_filter_http_total": { + "prior_p50": 137.83216592855752, + "native_p50": 168.2225419790484, + "native_first_sample": 164.90725002950057, + "native_maximum": 172.01900004874915 + } + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "checks": [ + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 33334 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 66666 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 66667 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1070", + "ref": "const,const,const", + "rows": 20, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + } + ], + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "38", + "ref": "const", + "rows": 827077, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 204390, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": null, + "rows": 204390, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "range", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 2951014, + "filtered": 100.0, + "Extra": "Using where; Using index for group-by (scanning)" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "index", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1108", + "ref": null, + "rows": 1654154, + "filtered": 100.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 12, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 3.526624999998603 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.08437079098075628 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.10236137500032783 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0004254169762134552 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 3.0357274590060115 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 0.09343941701808944 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 0.1018385419738479 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0004039999912492931 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s GROUP BY project_uuid,tag", + "seconds": 2.991644333000295 + }, + { + "sql": "SELECT tag,COUNT(DISTINCT target_kind,target_uuid) AS amount FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag", + "seconds": 4.095707458036486 + }, + { + "sql": "SELECT tag,profile_uuid,MAX(CAST(CONCAT(target_kind,'/',target_uuid) AS BINARY)) AS position FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) GROUP BY project_uuid,tag,profile_uuid", + "seconds": 4.103170584014151 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0005604579928331077 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_diagnostic_ms": { + "autocomplete_cold_diagnostic": 3740.355083020404, + "autocomplete_warm_diagnostic": 3255.884749989491, + "autocomplete_empty_diagnostic": 11217.491208051797 + }, + "initial_native_setup": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 1.488408 + } + }, + "project_uuid": "3a791e27-101f-4a82-a7e8-f8be38297694", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 1.672049 + }, + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.068396 + } + }, + "project_uuid": "3a791e27-101f-4a82-a7e8-f8be38297694", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.151797 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.052229 + } + }, + "project_uuid": "3a791e27-101f-4a82-a7e8-f8be38297694", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.165251 + }, + "seconds": 0.31707962503423914, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "same_server_native_reuse_filter_ms": 138.54400004493073, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:21:20.833735+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "mysql_version": "8.4.2", + "runtime_seconds": 223.9138767500408, + "seed_seconds": 127.78472875000443, + "seed_checkpoint_seconds": 13.33677566703409, + "owned_native_runtime_stopped": true + } + }, + "performance_complete": false, + "remaining_responsiveness_findings": [ + "At 100k, prefix autocomplete takes 3.3–3.7 seconds, dominated by the dictionary covering scan.", + "At 100k, empty autocomplete takes 11.2 seconds, adding full-vocabulary counts and winning positions.", + "The 100k two-save/filter sequence takes 203.0 ms versus the prior 166.0 ms; bounded point-tag SQL does not remove all metadata work." + ] +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-results.md b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-results.md new file mode 100644 index 0000000..4b61eb8 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-pre-dictionary-results.md @@ -0,0 +1,65 @@ +# Native SQL tag workflow validation + +The final native SQL runs pass at 500 and 100,000 epochs using the same verified source snapshot. Exact-membership, author/revision, hierarchy, removal, recovery-mirror and native-index checks pass. Neither run calls the legacy SQLite tag membership or refresh path. + +Performance is mixed. The 500-epoch two-save/filter sequence improves from 73.6 to 69.3 ms, while the 100k sequence measures 203.0 ms versus the prior 166.0 ms. At 100k, prefix autocomplete still takes 3.3–3.7 seconds and an empty query takes 11.2 seconds. Passing correctness checks does not establish that the responsiveness work is complete. + +Each fixture has three profiles, five seeded tags per annotation, cell annotations, and two independent protocol curation scopes. Five complete cycles read revisions and durably tag 10 epochs, read revisions and tag another 10 in another cell, then immediately filter the exact 20. + +| Operation (median milliseconds) | 500 prior | 500 native | 100k prior | 100k native | +|---|---:|---:|---:|---:| +| First 10 epochs: durable POST | 15.2 | 17.7 | 17.6 | 25.0 | +| Next 10 epochs: durable POST | 13.4 | 16.9 | 16.2 | 23.9 | +| Filter after the two saves: exactly 20 epochs | 31.1 | 23.2 | 119.2 | 126.0 | +| Two revision reads + two saves + filter | 73.6 | 69.3 | 166.0 | 203.0 | +| One cell: durable POST | 6.7 | 7.5 | 7.8 | 8.8 | +| Cell filter: exactly 100 inherited epochs | 41.5 | 38.8 | 129.8 | 160.0 | +| Cell AND epoch filter: exactly 10 epochs | 17.4 | 18.3 | 106.2 | 124.8 | +| Cell save + cell filter | 48.1 | 46.3 | 137.8 | 168.2 | + +The total uses paired per-cycle timings and includes both revision reads. POST timing ends after canonical MySQL save acknowledgment. The separately scheduled recovery mirror is flushed and checked after the operations. Timings include Flask HTTP client JSON decoding, not browser interaction or paint. + +The first filter request after seeding took 27.2 ms at 500 epochs and 227.2 ms at 100k; the first full sequences took 92.9 and 327.7 ms. Native application startup performs its metadata preparation; the harness performs no preparatory tag query or SQLite tag checkpoint after seeding. These are not cold MySQL/OS-cache measurements. Five samples do not establish tail-latency guarantees. + +## Index, persistence and correctness + +The actual 20-epoch filter uses the persistent `by_tag` covering index with `ref` access and an estimate of 20 lookup rows at both scales. Both runs distinguish `QC` from `qc` and NFC `é` from decomposed `é`; they verify AND, OR, NOT, inherited cell membership, direct-only epoch scope, exact author chips and revisions. Cell tagging changes one canonical cell record and creates no child annotation copies; both protocol curation scopes remain unchanged. + +A fresh Python lookup adapter reuses the persistent SQL table in the same server. Its exact-20 filter takes 20.7/138.5 ms at 500/100k. This is not a MySQL process restart. Initial preparation timing in the raw receipts precedes annotation seeding and is not a populated legacy-database migration benchmark. + +Both final backup receipts are `current`, with no pending/running work or error, and requested/completed sequence 34. The flushed recovery mirror matches all 63 tracked canonical records, including final removals. Both owned native servers stopped successfully. + +## Autocomplete diagnostic + +After the timed workflow, two calls use `q=gate&limit=12` and a third uses an empty query with `limit=12`. An independent seeded oracle verifies exact counts and profile authors for all returned tags. Each is one observation; first/repeated labels do not mean cold/warm storage. + +| Scale | First gate-prefix ms | Repeated gate-prefix ms | Empty query ms | +|---|---:|---:|---:| +| 500 | 23.3 | 29.4 | 33.3 | +| 100,000 | 3740.4 | 3255.9 | 11217.5 | + +The final query shape reads the tag dictionary through `by_tag`, filters the dictionary with the existing Unicode casefold prefix semantics, counts matching memberships through `by_tag`, and reads the chosen authors through complete literal canonical keys. The empty query still counts the complete vocabulary. Actual SQL, per-statement timings and EXPLAIN output are in each receipt. + +The 100k optimizer chooses a covering project-prefix scan for the dictionary (`by_tag`, `ref`, 827,077 estimated rows), not a loose distinct-tag scan. That query takes 3.0–3.5 seconds and dominates prefix autocomplete. The bounded prefix count and winning-position queries each take roughly 0.1 second; complete primary-key author reads take less than 1 ms (`PRIMARY`, key length 331, three chosen rows). For the empty query, counts and winning positions additionally take about 4.1 seconds each. No manual `ANALYZE` or other query-plan preparation was added to this benchmark. + +| Scale/request | SQL statement durations (ms, execution order) | +|---|---| +| 500 / cold | 1.9 / 0.5 / 0.8 / 0.3 | +| 500 / warm | 1.9 / 0.5 / 0.7 / 0.2 | +| 500 / empty | 1.9 / 5.2 / 6.0 / 0.3 | +| 100,000 / cold | 3526.6 / 84.4 / 102.4 / 0.4 | +| 100,000 / warm | 3035.7 / 93.4 / 101.8 / 0.4 | +| 100,000 / empty | 2991.6 / 4095.7 / 4103.2 / 0.6 | + +## Reproducible evidence + +- [Final 500-epoch receipt](native-tag-sequence-pre-dictionary-500.json) and [final 100,000-epoch receipt](native-tag-sequence-pre-dictionary-100000.json). +- [Prior SQLite 500-epoch receipt](tag-sequence-after-500.json) and [prior 100,000-epoch receipt](tag-sequence-after-100000.json). +- [Native harness](benchmark_native_tag_sequence.py), [machine-readable comparison](native-tag-sequence-pre-dictionary-results.json), and [source snapshot manifest](native-tag-source-pre-dictionary-snapshot.json). +- [Preserved provisional pre-autocomplete-fix report](native-tag-sequence-pre-autocompletefix-results.md): 100k correctness passed, but concurrent source edits invalidated its overall receipt; its gate-prefix autocomplete took 9–10 seconds. + +The final runs used one private copy of Python/config, the three harness dependencies, frontend source/package metadata needed by audit fingerprints, and retinanalysis source. The existing pinned runtime binaries were reused. Copy-time source/copy hashes matched; every copied file remained unchanged through both final runs. Both receipts additionally attest identical before/after Python inventories, harness hashes and loaded-module paths. Concurrent edits in the working checkout do not alter this measured snapshot. + +Native harness SHA-256: `468173271c08020e7e1a7ce8b0fcdfc59693be0f9e3699a8caec342b2e77affd`. + +These receipts validate the stated workflow and checks; they do not certify a complete desktop release. diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.json b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.json new file mode 100644 index 0000000..8c01322 --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.json @@ -0,0 +1,1462 @@ +{ + "scope": "Native SQL lookup versus prior SQLite tag cache, same scientist workflow. Disposable native database, synthetic acquisition metadata, HTTP test-client timings.", + "passed": true, + "source_and_harness_unchanged_across_both_native_runs": true, + "samples_per_workflow_operation": 5, + "snapshot_manifest": "native-tag-source-snapshot.json", + "native_harness_sha256": "26d058c7a3b9c5f67071e38d70df66a566b37cef7b543656b0bcb521c04df133", + "scales": { + "500": { + "native_receipt": "native-tag-sequence-500.json", + "prior_receipt": "tag-sequence-after-500.json", + "comparison_ms": { + "first10_save": { + "prior_p50": 15.186292002908885, + "native_p50": 20.486874971538782, + "native_first_sample": 44.35537499375641, + "native_maximum": 44.35537499375641 + }, + "second10_save": { + "prior_p50": 13.435167027637362, + "native_p50": 19.969207991380244, + "native_first_sample": 20.426875038538128, + "native_maximum": 22.125250019598752 + }, + "filter20": { + "prior_p50": 31.089458032511175, + "native_p50": 24.433874990791082, + "native_first_sample": 33.14845898421481, + "native_maximum": 33.14845898421481 + }, + "tag10_then10_filter20_http_total": { + "prior_p50": 73.59912293031812, + "native_p50": 77.54574995487928, + "native_first_sample": 116.95775098633021, + "native_maximum": 116.95775098633021 + }, + "cell_save": { + "prior_p50": 6.7298339563421905, + "native_p50": 8.321208006236702, + "native_first_sample": 12.93837500270456, + "native_maximum": 12.93837500270456 + }, + "filter_cell100": { + "prior_p50": 41.47870797896758, + "native_p50": 43.737958010751754, + "native_first_sample": 43.737958010751754, + "native_maximum": 61.345916998106986 + }, + "filter_cell_and_epoch10": { + "prior_p50": 17.395791015587747, + "native_p50": 22.31991698499769, + "native_first_sample": 19.91629198892042, + "native_maximum": 27.239874994847924 + }, + "cell_tag_then_cell_filter_http_total": { + "prior_p50": 48.06662496412173, + "native_p50": 51.80883401772007, + "native_first_sample": 56.676333013456315, + "native_maximum": 72.56833399878815 + } + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "checks": [ + { + "name": "populated_native_migration_ready_before_timed_operations", + "passed": true + }, + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "autocomplete_has_no_membership_aggregation", + "passed": true, + "membership_selects": 30, + "maximum_rows_per_seek": 1 + }, + { + "name": "autocomplete_compact_dictionary_fetches_are_bounded", + "passed": true, + "dictionary_selects": 9, + "scope": "Counts may scan matching compact entries; no unbounded dictionary rows are fetched for Python prefix filtering." + }, + { + "name": "autocomplete_membership_winner_seeks_are_indexed", + "passed": true, + "plans": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 167 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 333 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 250 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": "const,const", + "rows": 20, + "filtered": 10.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": "const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using index condition; Using filesort" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "38", + "ref": "const", + "rows": 41, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_rank", + "key": "by_rank", + "key_len": "38", + "ref": "const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 24, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 9, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.00012283300748094916, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.0001301250304095447, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00014424999244511127, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.00013224995927885175, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001396249863319099, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013120798394083977, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011324998922646046, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00016866601072251797, + "result_rows": 3 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0001443749642930925, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.000144040968734771, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.0001740000443533063, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.00016950001008808613, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00016325002070516348, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013179198140278459, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00019791699014604092, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00021045899484306574, + "result_rows": 3 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0002182909520342946, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "seconds": 0.00022295804228633642, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.0002453330089338124, + "result_rows": 12 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.0002537500113248825, + "result_rows": 24 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014916702639311552, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013404199853539467, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011974998051300645, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00017691700486466289, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013070798013359308, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011962500866502523, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012362503912299871, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012741703540086746, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001378749730065465, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013474997831508517, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001284580212086439, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001437499886378646, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013579102233052254, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013800000306218863, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011987495236098766, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011399999493733048, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011145800817757845, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011766701936721802, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011616700794547796, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012120796600356698, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00020866701379418373, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00018604198703542352, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010916695464402437, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010958401253446937, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.0004837500164285302, + "result_rows": 9 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_diagnostic_ms": { + "autocomplete_cold_diagnostic": 21.61020803032443, + "autocomplete_warm_diagnostic": 24.96337500633672, + "autocomplete_empty_diagnostic": 30.342624988406897 + }, + "initial_native_setup": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.06283 + } + }, + "project_uuid": "69b6a7e7-762d-4adf-ad65-b1c3a8eff7f1", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.436276 + }, + "fixture_construction": { + "strategy": "canonical seed before normal app startup and populated native migration", + "native_derived_tables_absent_during_seed": true, + "canonical_shared_records": 1515, + "canonical_curation_records": 1000, + "product_triggers_disabled_during_timed_operations": false + }, + "populated_native_startup_seconds": 1.002701541990973, + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.022153 + } + }, + "project_uuid": "69b6a7e7-762d-4adf-ad65-b1c3a8eff7f1", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.102921 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.02182 + } + }, + "project_uuid": "69b6a7e7-762d-4adf-ad65-b1c3a8eff7f1", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.175279 + }, + "seconds": 0.27823945798445493, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "same_server_native_reuse_filter_ms": 26.880667021032423, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:39:04.669427+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "mysql_version": "8.4.2", + "runtime_seconds": 11.342676208994817, + "seed_seconds": 0.08865733398124576, + "seed_checkpoint_seconds": 0.05130733299301937, + "owned_native_runtime_stopped": true + }, + "100000": { + "native_receipt": "native-tag-sequence-100000.json", + "prior_receipt": "tag-sequence-after-100000.json", + "comparison_ms": { + "first10_save": { + "prior_p50": 17.622290994040668, + "native_p50": 20.654458028730005, + "native_first_sample": 50.29199999989942, + "native_maximum": 50.29199999989942 + }, + "second10_save": { + "prior_p50": 16.18437498109415, + "native_p50": 24.3177090305835, + "native_first_sample": 22.857792035210878, + "native_maximum": 24.691416998393834 + }, + "filter20": { + "prior_p50": 119.21920796157792, + "native_p50": 128.1725830049254, + "native_first_sample": 231.92245897371322, + "native_maximum": 231.92245897371322 + }, + "tag10_then10_filter20_http_total": { + "prior_p50": 165.9542090492323, + "native_p50": 191.6327920043841, + "native_first_sample": 331.8292510230094, + "native_maximum": 331.8292510230094 + }, + "cell_save": { + "prior_p50": 7.809958013240248, + "native_p50": 7.998415967449546, + "native_first_sample": 7.998415967449546, + "native_maximum": 9.052958048414439 + }, + "filter_cell100": { + "prior_p50": 129.82887495309114, + "native_p50": 156.9541670032777, + "native_first_sample": 156.9541670032777, + "native_maximum": 164.91170797962695 + }, + "filter_cell_and_epoch10": { + "prior_p50": 106.19708400918171, + "native_p50": 115.23075000150129, + "native_first_sample": 122.18404200393707, + "native_maximum": 122.18404200393707 + }, + "cell_tag_then_cell_filter_http_total": { + "prior_p50": 137.83216592855752, + "native_p50": 164.95258297072724, + "native_first_sample": 164.95258297072724, + "native_maximum": 172.59591701440513 + } + }, + "sqlite_tag_cache_calls": { + "membership_index": 0, + "refresh": 0 + }, + "checks": [ + { + "name": "populated_native_migration_ready_before_timed_operations", + "passed": true + }, + { + "name": "native_autocomplete_exact_counts_and_profile_authors", + "passed": true + }, + { + "name": "autocomplete_has_no_membership_aggregation", + "passed": true, + "membership_selects": 30, + "maximum_rows_per_seek": 1 + }, + { + "name": "autocomplete_compact_dictionary_fetches_are_bounded", + "passed": true, + "dictionary_selects": 9, + "scope": "Counts may scan matching compact entries; no unbounded dictionary rows are fetched for Python prefix filtering." + }, + { + "name": "autocomplete_membership_winner_seeks_are_indexed", + "passed": true, + "plans": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "name": "actual_filter_uses_persistent_by_tag_sql_index", + "passed": true, + "queries": 1 + }, + { + "name": "persistent_native_lookup_reused_without_rebuild", + "passed": true + }, + { + "name": "exact_native_case_upper", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_case_lower", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_unicode_nfc", + "passed": true, + "count": 33334 + }, + { + "name": "exact_native_unicode_nfd", + "passed": true, + "count": 66666 + }, + { + "name": "exact_native_or", + "passed": true, + "count": 66667 + }, + { + "name": "exact_native_not_with_inheritance", + "passed": true, + "count": 50000 + }, + { + "name": "exact_native_inherited_excluded_from_direct", + "passed": true, + "count": 0 + }, + { + "name": "no_sqlite_tag_membership_or_refresh_used", + "passed": true, + "calls": { + "membership_index": 0, + "refresh": 0 + } + }, + { + "name": "canonical_final_markers_removed", + "passed": true + }, + { + "name": "flushed_recovery_mirror_exact_revisions_and_removal", + "passed": true, + "records": 63 + }, + { + "name": "one_canonical_cell_record_no_child_copies", + "passed": true, + "child_epochs": 100 + }, + { + "name": "independent_protocol_curation_untouched", + "passed": true + }, + { + "name": "all_product_modules_loaded_from_selected_source", + "passed": true + } + ], + "native_lookup_query_plans": [ + { + "sql": "SELECT DISTINCT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND target_kind IN (%s) AND tag=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1060", + "ref": "const,const", + "rows": 20, + "filtered": 10.0, + "Extra": "Using where; Using index; Using temporary" + } + ] + } + ], + "autocomplete_query_plans": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": "const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "range", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "1571", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using index condition; Using filesort" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_lookup", + "partitions": null, + "type": "ref", + "possible_keys": "by_tag", + "key": "by_tag", + "key_len": "1098", + "ref": "const,const,const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using where; Backward index scan; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 3, + "filtered": 100.0, + "Extra": "Using where" + } + ] + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_prefix", + "key": "by_prefix", + "key_len": "38", + "ref": "const", + "rows": 41, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_dictionary", + "partitions": null, + "type": "ref", + "possible_keys": "by_rank", + "key": "by_rank", + "key_len": "38", + "ref": "const", + "rows": 1, + "filtered": 100.0, + "Extra": "Using index" + } + ] + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "app_shared_tag_authors", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "1060", + "ref": null, + "rows": 24, + "filtered": 100.0, + "Extra": "Using where; Using index" + } + ] + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "explain": [ + { + "id": 1, + "select_type": "SIMPLE", + "table": "shared_annotation", + "partitions": null, + "type": "range", + "possible_keys": "PRIMARY", + "key": "PRIMARY", + "key_len": "331", + "ref": null, + "rows": 12, + "filtered": 100.0, + "Extra": "Using where" + } + ] + } + ], + "autocomplete_sql": { + "autocomplete_cold_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0001382920308969915, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.0001492909505032003, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00015729200094938278, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.0001496669719927013, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00015233299927785993, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013812503311783075, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013883301289752126, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00019345799228176475, + "result_rows": 3 + } + ], + "autocomplete_warm_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.00014100002590566874, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s", + "seconds": 0.00015254097525030375, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key>=%s AND fold_key<%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00016245798906311393, + "result_rows": 3 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s)", + "seconds": 0.00017329101683571935, + "result_rows": 3 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00016587501158937812, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014037505025044084, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001366669894196093, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00019987503765150905, + "result_rows": 3 + } + ], + "autocomplete_empty_diagnostic": [ + { + "sql": "SELECT tag FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s AND fold_key IS NULL LIMIT 200", + "seconds": 0.0002447500010021031, + "result_rows": 0 + }, + { + "sql": "SELECT COUNT(*) AS amount FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_prefix) WHERE project_uuid=%s", + "seconds": 0.00015116599388420582, + "result_rows": 1 + }, + { + "sql": "SELECT tag,target_count FROM `recording_workspace`.`app_shared_tag_dictionary` FORCE INDEX (by_rank) WHERE project_uuid=%s ORDER BY target_count DESC,fold_key,tag LIMIT %s", + "seconds": 0.00016816600691527128, + "result_rows": 12 + }, + { + "sql": "SELECT tag,profile_uuid FROM `recording_workspace`.`app_shared_tag_authors` WHERE project_uuid=%s AND tag IN (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", + "seconds": 0.00023812497965991497, + "result_rows": 24 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014874996850267053, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00017024995759129524, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00029045797418802977, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012725003762170672, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00020070798927918077, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001289580250158906, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013695796951651573, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012425001477822661, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00012670899741351604, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011995801469311118, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011025002459064126, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011108402395620942, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.0001033750013448298, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011508399620652199, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011308299144729972, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00014779099728912115, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011537497630342841, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010775000555440784, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011224998161196709, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010175001807510853, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010091596050187945, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00010791700333356857, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00013529200805351138, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid FROM `recording_workspace`.`app_shared_tag_lookup` FORCE INDEX (by_tag) WHERE project_uuid=%s AND tag=%s AND profile_uuid=%s ORDER BY target_kind DESC,target_uuid DESC LIMIT 1", + "seconds": 0.00011187494965270162, + "result_rows": 1 + }, + { + "sql": "SELECT target_kind,target_uuid,profile_uuid,author_name FROM `recording_workspace`.`shared_annotation` WHERE project_uuid=%s AND (target_kind,target_uuid,profile_uuid) IN ((%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s),(%s,%s,%s))", + "seconds": 0.00030766602139919996, + "result_rows": 12 + } + ] + }, + "autocomplete_requests": { + "autocomplete_cold_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_warm_diagnostic": { + "q": "gate", + "limit": 12, + "total": 3 + }, + "autocomplete_empty_diagnostic": { + "q": "", + "limit": 12, + "total": 41 + } + }, + "autocomplete_diagnostic_ms": { + "autocomplete_cold_diagnostic": 22.329957981128246, + "autocomplete_warm_diagnostic": 20.90041700284928, + "autocomplete_empty_diagnostic": 25.776874972507358 + }, + "initial_native_setup": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 1.508189 + } + }, + "project_uuid": "4dff9ec3-f69a-4387-9e77-a43eb4b14f4a", + "reused": false, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 128.9519 + }, + "fixture_construction": { + "strategy": "canonical seed before normal app startup and populated native migration", + "native_derived_tables_absent_during_seed": true, + "canonical_shared_records": 303000, + "canonical_curation_records": 200000, + "product_triggers_disabled_during_timed_operations": false + }, + "populated_native_startup_seconds": 144.54315195797244, + "same_server_native_lookup_reuse": { + "checkpoint": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.054597 + } + }, + "project_uuid": "4dff9ec3-f69a-4387-9e77-a43eb4b14f4a", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.139045 + }, + "reopened": { + "status": "ready", + "storage": "native_sql", + "phases": { + "preparing_protocol_reads": { + "seconds": 0.052419 + } + }, + "project_uuid": "4dff9ec3-f69a-4387-9e77-a43eb4b14f4a", + "reused": true, + "protocols_prepared": 2, + "protocols_deferred": 0, + "phase": "complete", + "seconds": 0.181751 + }, + "seconds": 0.32084808399667963, + "scope": "Native lookup checkpoint followed by a fresh Python lookup adapter in the same server; not a MySQL-process restart." + }, + "same_server_native_reuse_filter_ms": 120.17941597150639, + "final_backup_status": { + "status": "current", + "pending": false, + "running": false, + "last_success": "2026-09-30T15:43:05.619622+00:00", + "last_error": null, + "requested_sequence": 34, + "completed_sequence": 34 + }, + "mysql_version": "8.4.2", + "runtime_seconds": 219.8653925419785, + "seed_seconds": 14.418896374991164, + "seed_checkpoint_seconds": 0.03377008403185755, + "owned_native_runtime_stopped": true + } + }, + "query_architecture_gates_passed": true, + "workflow_uniformly_faster_than_prior_sqlite": false, + "limitations": [ + "The 100k two-save/filter median is 191.6 ms versus the prior 166.0 ms; other metadata and response work remains.", + "Populated 100k application startup/migration took 144.543 seconds; subsequent same-server lookup-adapter preparation reused the structures in 0.182 seconds.", + "The exact empty-query total counts 41 compact dictionary entries; no membership aggregation or unbounded dictionary row fetch occurs." + ], + "autocomplete_100k_sql_summary": { + "autocomplete_cold_diagnostic": { + "statements": 8, + "seconds": 0.0012172909919172525, + "maximum_statement_seconds": 0.00019345799228176475 + }, + "autocomplete_warm_diagnostic": { + "statements": 8, + "seconds": 0.001272082095965743, + "maximum_statement_seconds": 0.00019987503765150905 + }, + "autocomplete_empty_diagnostic": { + "statements": 29, + "seconds": 0.0042779138893820345, + "maximum_statement_seconds": 0.00030766602139919996 + } + } +} diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.md b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.md new file mode 100644 index 0000000..55ffdfe --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-sequence-results.md @@ -0,0 +1,62 @@ +# Native SQL tag workflow validation + +The final native SQL runs pass at 500 and 100,000 epochs using the same verified source snapshot. Exact-membership, author/revision, hierarchy, removal, recovery-mirror and native-index checks pass. Neither run calls the legacy SQLite tag membership or refresh path. At 100k, autocomplete now takes 21–26 ms, versus 3.3–3.7 seconds for a prefix and 11.2 seconds for an empty query before the compact dictionary. + +Each fixture has three profiles, five seeded tags per annotation, cell annotations, and two independent protocol curation scopes. Canonical rows are bulk-seeded before normal application startup installs and backfills native tag structures. No triggers are disabled for timed operations. Five complete cycles read revisions and durably tag 10 epochs, read revisions and tag another 10 in another cell, then immediately filter the exact 20. + +| Operation (median milliseconds) | 500 prior | 500 native | 100k prior | 100k native | +|---|---:|---:|---:|---:| +| First 10 epochs: durable POST | 15.2 | 20.5 | 17.6 | 20.7 | +| Next 10 epochs: durable POST | 13.4 | 20.0 | 16.2 | 24.3 | +| Filter after the two saves: exactly 20 epochs | 31.1 | 24.4 | 119.2 | 128.2 | +| Two revision reads + two saves + filter | 73.6 | 77.5 | 166.0 | 191.6 | +| One cell: durable POST | 6.7 | 8.3 | 7.8 | 8.0 | +| Cell filter: exactly 100 inherited epochs | 41.5 | 43.7 | 129.8 | 157.0 | +| Cell AND epoch filter: exactly 10 epochs | 17.4 | 22.3 | 106.2 | 115.2 | +| Cell save + cell filter | 48.1 | 51.8 | 137.8 | 165.0 | + +The broader save/filter workflow has not become uniformly faster: its 100k median is 191.6 ms versus the prior 166.0 ms. The native point lookup is indexed, while other metadata and response work remains. The total uses paired per-cycle timings and includes both revision reads. POST timing ends after canonical MySQL save acknowledgment. The separately scheduled recovery mirror is flushed and checked after the operations. Timings include Flask HTTP client JSON decoding, not browser interaction or paint. + +The first filter request after seeding took 33.1 ms at 500 epochs and 231.9 ms at 100k; the first full sequences took 117.0 and 331.8 ms. Native application startup performs its metadata preparation; the harness performs no preparatory tag query or SQLite tag checkpoint after seeding. These are not cold MySQL/OS-cache measurements. Five samples do not establish tail-latency guarantees. + +## Index, persistence and correctness + +The actual 20-epoch filter uses the persistent `by_tag` covering index with `ref` access and an estimate of 20 lookup rows at both scales. Both runs distinguish `QC` from `qc` and NFC `é` from decomposed `é`; they verify AND, OR, NOT, inherited cell membership, direct-only epoch scope, exact author chips and revisions. Cell tagging changes one canonical cell record and creates no child annotation copies; both protocol curation scopes remain unchanged. + +A fresh Python lookup adapter reuses the persistent SQL table in the same server. Its exact-20 filter takes 26.9/120.2 ms at 500/100k. This is not a MySQL process restart. Initial preparation now measures normal startup on the populated canonical fixture, including native backfill, content proof and bounded protocol preparation. The raw receipt separately records total application startup and canonical fixture construction. + +The populated migration cost is explicit: canonical seeding took 0.089/14.419 seconds at 500/100k; normal application startup took 1.003/144.543 seconds, including 0.436/128.952 seconds in native annotation preparation. At 100k this creates lookup/dictionary structures for 303,000 canonical shared-annotation records. Subsequent same-server preparation with a fresh lookup adapter reused those structures in 0.182 seconds; this does not measure a full desktop restart. + +Both final backup receipts are `current`, with no pending/running work or error, and requested/completed sequence 34. The flushed recovery mirror matches all 63 tracked canonical records, including final removals. Both owned native servers stopped successfully. + +## Autocomplete diagnostic + +After the timed workflow, two calls use `q=gate&limit=12` and a third uses an empty query with `limit=12`. An independent seeded oracle verifies exact counts and profile authors for all returned tags. Each is one observation; first/repeated labels do not mean cold/warm storage. + +| Scale | First gate-prefix ms | Repeated gate-prefix ms | Empty query ms | +|---|---:|---:|---:| +| 500 | 21.6 | 25.0 | 30.3 | +| 100,000 | 22.3 | 20.9 | 25.8 | + +Autocomplete now queries the persisted compact dictionary with maintained distinct-target counts and stored Unicode fold keys. Profile references come from the compact author table; any membership reads are bounded `by_tag` winner seeks returning at most one row, followed by complete canonical primary-key reads. Harness gates reject membership aggregates and unbounded dictionary row fetches. An exact total may count matching compact dictionary entries. Actual SQL, returned row counts, per-statement timings and EXPLAIN output are preserved. + +At 100k, prefix count/ranking uses `by_prefix` range access over three dictionary entries. Empty-query ranking uses `by_rank` with a 12-row limit; its exact total counts 41 compact dictionary entries. Membership winner reads use `by_tag` with project/tag/profile keys, backward index traversal and `LIMIT 1`; canonical author reads use the full primary key (length 331). There is no membership aggregation or unbounded dictionary fetch into Python. + +| 100k request | Traced tag SQL statements | Combined tag SQL time | Slowest statement | +|---|---:|---:|---:| +| First gate prefix | 8 | 1.22 ms | 0.19 ms | +| Repeated gate prefix | 8 | 1.27 ms | 0.20 ms | +| Empty query | 29 | 4.28 ms | 0.31 ms | + +## Reproducible evidence + +- [Final 500-epoch receipt](native-tag-sequence-500.json) and [final 100,000-epoch receipt](native-tag-sequence-100000.json). +- [Prior SQLite 500-epoch receipt](tag-sequence-after-500.json) and [prior 100,000-epoch receipt](tag-sequence-after-100000.json). +- [Native harness](benchmark_native_tag_sequence.py), [machine-readable comparison](native-tag-sequence-results.json), and [source snapshot manifest](native-tag-source-snapshot.json). +- [Pre-dictionary baseline](native-tag-sequence-pre-dictionary-results.md): immutable-source correctness passed, but 100k prefix autocomplete took 3.3–3.7 seconds and empty autocomplete 11.2 seconds. The earlier [provisional report](native-tag-sequence-pre-autocompletefix-results.md) remains preserved with its source-change limitation. + +The final runs used one private copy of Python/config, the three harness dependencies, frontend source/package metadata needed by audit fingerprints, and retinanalysis source. The existing pinned runtime binaries were reused. Copy-time source/copy hashes matched; every copied file remained unchanged through both final runs. Both receipts additionally attest identical before/after Python inventories, harness hashes and loaded-module paths. Concurrent edits in the working checkout do not alter this measured snapshot. + +Native harness SHA-256: `26d058c7a3b9c5f67071e38d70df66a566b37cef7b543656b0bcb521c04df133`. + +These receipts validate the stated workflow and checks; they do not certify a complete desktop release. diff --git a/docs/dev/scale-audit-2026-09-29/native-tag-source-snapshot.json b/docs/dev/scale-audit-2026-09-29/native-tag-source-snapshot.json new file mode 100644 index 0000000..0d275bb --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native-tag-source-snapshot.json @@ -0,0 +1,564 @@ +{ + "created_at": "2026-09-30T15:38:40.119352+00:00", + "source_root": "/Users/maxwellsdm/Documents/GitHub/epicTreeGUI", + "snapshot_root": "/private/var/folders/41/tclkvrfs1v9386sxps6_w5t40000gn/T/rieke-native-tags-frozen-3hwp8_rq", + "copy_was_stable": true, + "source_files": { + ".rieke-runtime/retinanalysis/src/.DS_Store": "930bc23ea1d7e34b68d9e4a27682d176bce3e59fd319dc837c65f3d9872a315d", + ".rieke-runtime/retinanalysis/src/retinanalysis/.DS_Store": "a63ad641449dc2397feb8049373ee6956c282557fe2a0355bef20883596ed956", + ".rieke-runtime/retinanalysis/src/retinanalysis/__init__.py": "77cfc5692391f123c633adb6d52d96a12d5a6200ac7079f6ddfbeb130d2f27b9", + ".rieke-runtime/retinanalysis/src/retinanalysis/_database.py": "ac13b09d29067430928248f6713571231da2a8d8231c2917563b9bf3f7435b3c", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cell_types.csv": "da09e4cf6b3c12f67688ac460ba8fdfee94da69c96b0c18b3dd60dfc077bbae6", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/classification_files/20250514C/movingLetters_chunk3_autoClassification.txt": "cc5dd63d7904923d1be10a076b2fbf4a7f781ac490016ef0da06ea3e412e5637", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/mouse/m_cone_spectrum.txt": "b755579e2b3d0b75de379c93e3a21d0b5f50b3dffd7fe5b780373fd713bce9f9", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/mouse/rod_spectrum.txt": "87cf8c8fced8e775d29d501108163b802dc418755db4ff6988c793e6ec7a8706", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/mouse/s_cone_spectrum.txt": "ad27d242413fe15f1082a4142877f96716b64030f511d91ba5c978b3eb8f9bdb", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/primate/l_cone_spectrum.txt": "4ee94d5e1062b6fa972c6f7501739d5ae4bffc27ff4a26c8315f61f06eb96d99", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/primate/m_cone_spectrum.txt": "3d3fb74bf345422bcfc47b93067a3dc894eccda1e9a2f118f3c387e3f85d5698", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/primate/rod_spectrum.txt": "7782cf580e6627e045941e94371f848da4e237f2ad114ff1b356e3fa76fb8eb7", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/primate/s_cone_spectrum.txt": "b179d17b4423fe13bef40aaa0e9653d75734f8845745033e9a69d93ea26eb057", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/zebrafish/l_cone_spectrum.txt": "657b31bf03681caf4c213a0ce7d1d3bafd9961909ddee2d1c79a673e84b1f584", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/zebrafish/m_cone_spectrum.txt": "b4f28c22ac948b8774d516add9cd913b9b30997eb3ad2eeb550c223752e678b7", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/zebrafish/rod_spectrum.txt": "eea4957a60ea0dd2a34675e4ba3719f2c59d2daf4fa79b602cd9b854dbdb5271", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/zebrafish/s_cone_spectrum.txt": "28fbfbc6b2c8f2697089231e290905ed2f5104bde9404d211669f0c1af52b6c6", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/cone_spectra/zebrafish/uv_cone_spectrum.txt": "7bfa3ef8bbe4e96ce59b1628130d864d00d731620856331e80e2df24a671a6c2", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/nd_filters/suction505.json": "f8a83db6d52c88e060f790479df1abfb7e20156786af00db6334aa4c0537fe58", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/nd_filters/suction565.json": "f3992f83fc98b904f33438466886642d7dd60de105ad495f66febc79ab6c5029", + ".rieke-runtime/retinanalysis/src/retinanalysis/assets/nd_filters/tinymea.json": "2070440c0bd7f38b6273f9b988ece2da7b2b21366ab9bcf8a5c5e8d7ca970bf1", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/analysis_chunk.py": "02caa277411066356ac04ee54722d7d6fd4ecc1e4e28e344b36b0ac06f2b73f2", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/dedup.py": "db5298777a41f8fb43b9b596bd739eed408f631e916c241cee8460843fcbcca5", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/mea_pipeline.py": "3740fd4905b663cc2443c53be072d9c8267fcf18ff8d5a3ad20f4aadf5121c64", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/qc.py": "4deb28211c07f4ad3386df30f4df29075758e78da2f7ad14f35b30ddf98463f4", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/raw.py": "85b71022f6e3b80a2610567916e385c7e803f34108179b59c2baa97b7ef005be", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/response.py": "8ebcee32916f6e081597a7b8b06acabe1029ca45140eb411a399f63a869bc7a6", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/sc_pipeline.py": "038d2afb60a4b0c6a201f88bc7223cf0665819da750e8452bbc6465c1652b3c9", + ".rieke-runtime/retinanalysis/src/retinanalysis/classes/stim.py": "8e8b6782f6b13046b7c5abf82250c6cf176638b356d2ac81e07ec808365395a8", + ".rieke-runtime/retinanalysis/src/retinanalysis/config/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + ".rieke-runtime/retinanalysis/src/retinanalysis/config/config.ini": "737be1cbac752a8cd62746b0c9d4393b4344c4f2245356dc14b76d75cb094c61", + ".rieke-runtime/retinanalysis/src/retinanalysis/config/config_create.py": "b60fef2624c552e66a999fc763c8364249f4df1049d12af62a67d1ac7e205fff", + ".rieke-runtime/retinanalysis/src/retinanalysis/config/schema.py": "13abf98c831dd4906e8e3c1fe3c79e2e0b28269ef329f5682def12beb82cb5bb", + ".rieke-runtime/retinanalysis/src/retinanalysis/config/settings.py": "da0c4354f5d19c02cd8bb826d63c9cb8461f892bc666986a0ee8a3b20ad63909", + ".rieke-runtime/retinanalysis/src/retinanalysis/preprocessing/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + ".rieke-runtime/retinanalysis/src/retinanalysis/preprocessing/ei_merge.py": "73b202081c9e9d2745e53177ef1a5bfe107d15569ece75845ce2b8ea91ac7cdb", + ".rieke-runtime/retinanalysis/src/retinanalysis/preprocessing/ks_to_vision.py": "4522cda7967eeb8f5d2efbd170b55548df3697c68c6b08d452c398727566916d", + ".rieke-runtime/retinanalysis/src/retinanalysis/preprocessing/rfs.py": "9e60c6a85b5c965bc0479adf6d6dc1d3ae6c8eb775b963351a4fa1fe33fba2f4", + ".rieke-runtime/retinanalysis/src/retinanalysis/preprocessing/sta.py": "1194b1283ed08aba331d4509102aa1e9f5840190170f8dd05b672172dd53d9e8", + ".rieke-runtime/retinanalysis/src/retinanalysis/sorting/run_vision_ss.sh": "64d3242812cd422f8916a35075e8e3ec1a6bf35210a2e6b5a6b6c9b4e085e75d", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/__init__.py": "f55619d98ca30d15d719ab6b636333cdd7984cf2dbf8e224995a0778f0f1a69a", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/database_pop.py": "54cf9c50e646308b4ce1e59065c2b1c06b09ae88a8c36ea6099ac75cee061411", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/database_utils.py": "c3dbf59feb749b6caa8c555cfc6d6b91d32d60d9b97f83d148972b821436d3a7", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/datajoint_utils.py": "6fb4f8bebf1acb4552576e560a29ead16b87836c6914b9b4f79736203d2855b5", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/ei_utils.py": "2b0b65525272ad85df9851d5268facaf7b8f7580516156010a0cf021544b455b", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/parse_data.py": "0d63fa4df6e087cda60fd85305ea3c4a7d287949abab325b9f1dd2e5f12779d2", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/regen.py": "609021eb6c5bed9588a9617b97b825ffdb897fd19ab59b94d69f5fa6f1d591f5", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/spike_detector.py": "6ab1419b5bf7218b5fb00e8435ecd0ab8b6daa1ee33a70550911823617aed739", + ".rieke-runtime/retinanalysis/src/retinanalysis/utils/vision_utils.py": "3fce9b896cc3639ea4005ecc272a02ce2debdcc0029f4687197d26c09373b2c4", + "docs/dev/scale-audit-2026-09-29/benchmark_native_tag_sequence.py": "26d058c7a3b9c5f67071e38d70df66a566b37cef7b543656b0bcb521c04df133", + "docs/dev/scale-audit-2026-09-29/benchmark_scientist_tag_workflow.py": "272fe050c8762ed4ea45bd013e236e8723d8fe46f5e7e293c58e2edf1fd52ddc", + "docs/dev/scale-audit-2026-09-29/benchmark_service_scale.py": "38caf8353c7040d2ba691edde81de751324a259a87acdf9f77bd02823d9d8e92", + "python/.pytest_cache/.gitignore": "3ed731b65d06150c138e2dadb0be0697550888a6b47eb8c45ecc9adba8b8e9bd", + "python/.pytest_cache/CACHEDIR.TAG": "37dc88ef9a0abeddbe81053a6dd8fdfb13afb613045ea1eb4a5c815a74a3bde4", + "python/.pytest_cache/README.md": "73fd6fccdd802c419a6b2d983d6c3173b7da97558ac4b589edec2dfe443db9ad", + "python/.pytest_cache/v/cache/lastfailed": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", + "python/.pytest_cache/v/cache/nodeids": "2fde60015384781ae0e52876e70ab08fa1c7c8725e8f61d9f681cb637d468d45", + "python/.pytest_cache/v/cache/stepwise": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", + "python/__init__.py": "6631251543e036e4b9bb74daabaacd0421877388e0900e12da92c464fd1127cb", + "python/benchmark_workspace_metadata.py": "34396f00dbf9125ee040c30b9be86ca42b03a0f9f0d8280335b352ad73a9a0c0", + "python/export_mat.py": "bb7179baefb9f5d09d593769747fe91b3e62702833cd46790d1b15bad4b16fe2", + "python/field_mapper.py": "7d02cd79bbb73f84e513ddda4436bb9fa4601877b7794f8fbf2a694d3321609b", + "python/import_ugm.py": "84efca3868208c062710acc1bbc426ee9512c7eb0a90ea5acbf463db07d06f6c", + "python/manage_workspace_storage.py": "3a9a30b0ae971031b6b6c082676cd801bbb0218c6045452b25d4ef9ca68d5ebe", + "python/query_protocol_workspace.py": "a09054aa63228effbd54a60cb479dd4431d16b46650d844ec92e5775347d329f", + "python/query_workspace_export.py": "9397c79664375f32a438619ca6d3654225aec5dc03a9847ce37afa99e475aad6", + "python/recording_workspace.py": "d81d9c5e03e62024c30474612596ee3fec2753a745e39c2db005010c85b8ffff", + "python/requirements.txt": "22b6b140bffbde7685a14e636d1580177d6f17a09fcc6880687d35e5399135e0", + "python/snapshot_protocol_workspace.py": "4e0b01ba212b8862f6f63e54064144e8108a8fe76978945b9842cb65d70052b9", + "python/tests/__init__.py": "814e202d031e0f73ca168aa5c712a3b7e0f1a8f2cd8ddc9a64e3d7ec987b9ac2", + "python/tests/test_desktop_release.py": "d35ae42a5b649ae02cd71474de2361a4ff51c251987cae2d65e9e09d9ea42e0f", + "python/tests/test_desktop_runtime_audit.py": "60b96a141e90e6f61f36b6c038cf8bf3464a643a92170964304d3cb78d8b5ef4", + "python/tests/test_desktop_runtime_packaging.py": "e2023fd3f7175e442968b9632845b38fa9d1f5659662286c0c52ae752de64876", + "python/tests/test_desktop_test_release.py": "912c946581e5668c69c44a1c7824bef1b2fdd7304b50d42a227c1b25b4e03e08", + "python/tests/test_export.py": "0814aa8279dbbb4a0adbaa7a624c70066699236867c422169351f36bc28b655f", + "python/tests/test_recording_workspace.py": "e1caa26a9b3d54193d6594f89f9abd0b04b47afdfa5bae494a260e4120188cfa", + "python/tests/test_workspace_annotation_density.py": "66d66d68054719f5b9e14cb2024146862d5883388cc7afececc9050ccac96af4", + "python/tests/test_workspace_annotation_preparation.py": "e8b62c2d3dfda9969ccc7e1697338a3141209a06ae4b18633772091967b795cd", + "python/tests/test_workspace_annotations.py": "0c7a411dcc2a54c4ae2742afcc61aa6e8c0ed43c4c83d3d568b8a5803201764f", + "python/tests/test_workspace_api.py": "31c2647b0bebe8e62b37a939d8d53cfbb19398c25f578c371ffef41c763fb935", + "python/tests/test_workspace_app_routes.py": "884434fedf25b1b82a94944f84c00e9fad9b81ddb4c56fcdaab8ac22b7a216a5", + "python/tests/test_workspace_audit.py": "2366c63b57422b0e5a77cb4e01aab752a368b668568576c2a539138c3b425a27", + "python/tests/test_workspace_author_preferences.py": "eb28fccb9e18d769c18635797d229227717b617cb31e30d12de499b7538e2b5c", + "python/tests/test_workspace_backend_responsiveness.py": "352017c0ea1a90be0597758578340847fe736c7f6d2c906b2d5bc6a57f118656", + "python/tests/test_workspace_backup_scheduler.py": "47d06824147bafb64b4b9c6741cc1465a421e6be7c6f058732e63c733a6a7a9f", + "python/tests/test_workspace_bootstrap.py": "a781c66702903781dcb733abfdf6aa9348fe0994e8ba92e8ef9c863d1f568b38", + "python/tests/test_workspace_cache_lifecycle.py": "2d50c23f856a365b1beaee8ee7d2aaa563e5ecb3e8dfbe121e8838e0fcd90494", + "python/tests/test_workspace_cache_publication.py": "cf3194e38d97fa89c351654e9ecddd69990eac7c5c82f9fb85631ff680e5f558", + "python/tests/test_workspace_candidate_exports.py": "0ca17b614df4ba8258e1fc8ae111d13358316debd6b2e13122a8361ff401a904", + "python/tests/test_workspace_catalog_collision.py": "6f9639e8e083399b30d0db61f5d784c21c295e4cf18dbb195776a478be157251", + "python/tests/test_workspace_catalog_identity.py": "8c5cfceeb6a6d7dffb34650a0a0061ea0c5efac33aa615a298d038afffa5463b", + "python/tests/test_workspace_catalog_optimization.py": "c5fdfdeb629d9f31a94fc04a49f27bee36e03a0a87c3f02d9cf370232de2d8b4", + "python/tests/test_workspace_combinations.py": "8be5d4ba2aedde78c1b01fe7a0495b5ce22862a4cdaf8a6f7ef39bb564a8bf26", + "python/tests/test_workspace_compact_explorer.py": "9073fab984393fe9b33af6971f7164ce287ab335e6cfaae58816fa667796073b", + "python/tests/test_workspace_concurrent_requests.py": "f074a762536ab5bb52abe4ea56faada41babb1cd765512acb3caba18dd503648", + "python/tests/test_workspace_curation.py": "9bff9716ec32af3a43176cfac0d38640469b9c88da17e2f97ccaedbea2fd209f", + "python/tests/test_workspace_curation_batch.py": "33c4b53abbac16401914f649ca5d9dab16d2b9bf89424253e8f9eeac7669dd13", + "python/tests/test_workspace_datastore_migration.py": "232f95f1c177b768643d73a9e5dd332344928b381374a374e663b6672eddc888", + "python/tests/test_workspace_datastores.py": "2db26628554f0a61af9122fef079099d65c9700400d928402026f29eb15ffd1c", + "python/tests/test_workspace_desktop.py": "b70fe1d82baa6ab40901d17e49ef8946297379a6d1adc3929a9cb979ae947e5a", + "python/tests/test_workspace_desktop_paths.py": "be12fb413ea6e2f3777f440c158e29480719991c6987433e53b14ac5865d08d6", + "python/tests/test_workspace_diff.py": "ece3af5b165588361c6d23be32c2706f5a96c95242db0f7542a4579b46e3c2f7", + "python/tests/test_workspace_disk_index.py": "ae4c272cc0faa24885f9a4bb7282e43a3c6a892da04cf8d096136010b49d6736", + "python/tests/test_workspace_disk_index_crash.py": "14f8fb2ae81180f888aef4246893c04f4528c7870c1167835f6b7911ea79f5f8", + "python/tests/test_workspace_empty_blocks.py": "ff0973074a72cf110b90dd8f76f032d5016315bbb21f84569e9fa701b11a7d88", + "python/tests/test_workspace_epoch_page_performance.py": "e21ee24baee1f473273503e51d1e92b80e95083dd463a3967860e90cadff4462", + "python/tests/test_workspace_event_paging.py": "e79cd1de3bd7469818e255cc01f087a608c11e799a48e81e4ca0ac29ff7a578e", + "python/tests/test_workspace_export_paths.py": "070b987b09afb06090bcafda808706316d272f20a24b5d09776bebf73a98002c", + "python/tests/test_workspace_export_reader.py": "ee260e95c19c4184c07f66633876bbd889abea14c8065cc17e8e8f253b408bbd", + "python/tests/test_workspace_external_tags.py": "25389f6868db35877a9a7564c9be32f786684c1cdac88ed43f8e1a2881abc807", + "python/tests/test_workspace_folder_browser.py": "1f111e4e2938b402be70ecd05849002cf2def5e7fb9c2470aa54928e635ccf9b", + "python/tests/test_workspace_frontend.py": "086ce8b19abaca47511f123f482072d40f48862ebe0c5361b1d48bc016f1f3e0", + "python/tests/test_workspace_generation_portability.py": "31cf7f52d275a9892366aa9e54d66ff12e0be2f70967722d3c179ef4b7f0f3b2", + "python/tests/test_workspace_h5_inbox.py": "ebb20a6daf67e245cfdd89c8abff75634bc6aa82f4bc859636caea1b66b918cc", + "python/tests/test_workspace_handoffs.py": "595b55c8343db1cee429914a329c6fb0d16e1b8edc8e4037c651d4e2b3250883", + "python/tests/test_workspace_identity_conflicts.py": "85aca1903054f632dc26b5f0d018c4b6e1163b848bcef1b740c2735de6eece7a", + "python/tests/test_workspace_import_api.py": "96dd94451b324cb157b2c694fac6fa09e449683f6a570e565d12fe483027fc45", + "python/tests/test_workspace_import_check.py": "c4b862ed07a803b1a86b22233b93db37c01a6b79d0296f8945960b372e4fc211", + "python/tests/test_workspace_import_identities.py": "e62c6c5df029329ae9b42b326a904e75699b068e899627951c7e05a8a5bbf655", + "python/tests/test_workspace_import_progress.py": "599a6962aed71928f85edc64daa4383ef07c0e81b1d9aa793a467437c602739d", + "python/tests/test_workspace_import_progress_failures.py": "32e838db0652c4c01f557e45ca54813ba34564bf7577f44a3e90b4fdb4bad88d", + "python/tests/test_workspace_import_worker_lease.py": "bc790683e5005027e2931e5c825a9fe64ac738f6931214315e68f32527e9b8cb", + "python/tests/test_workspace_installation.py": "e455e788040ce4f5f05a2dbf1e3c764f675aa6d6ff0a6ff4b2fc450b3b5e483e", + "python/tests/test_workspace_lifecycle.py": "e004025f8124fb8281edd222087c08399927763f8d1638240320b6107b570773", + "python/tests/test_workspace_mask_refresh.py": "a16cf823fab7a30b18b31489951d4844d54b4904552a70910f97209e2583c8ff", + "python/tests/test_workspace_matching_epochs.py": "162460c2a57676a32a9f703a4da9fe296f6e2be651c61893eed9e2244e562225", + "python/tests/test_workspace_matlab.py": "57be7801220f1a5ded314f402992002d78e84ddab608206887655c0018b971a9", + "python/tests/test_workspace_matlab_masks.py": "9f8e9819bc4322ed2b59218936a637c56b3aa256eb3dce8b8dc8683cde1dbab1", + "python/tests/test_workspace_matlab_routes.py": "740f681ad4fb7967eecfc47d3de8a50daa461b8c093ade901533d5657a6f33ce", + "python/tests/test_workspace_metadata_object_contract.py": "3694f9ffdbf19f96f4451efacc704bba837042fc80450d35d96e564dc068c6c1", + "python/tests/test_workspace_metadata_objects.py": "59a82e532d17d786a65c6a89d5ad8073920c9549f0429c1dc915c263b1b60f51", + "python/tests/test_workspace_metadata_refresh_api.py": "56b0858dbb422a5599411bd7a97c2b99f2368a8cd660f94bf6dd1aac9c0612a5", + "python/tests/test_workspace_migration.py": "2cac6f1ec33df1b7d7ef24b58f0ab6fb71730a12c5c6acf28c35f822e6aaed78", + "python/tests/test_workspace_mysql_runtime.py": "4b08894222ae6b85bfe39585927dae739bb00445f7d7f3f7e5d79f905a40b32f", + "python/tests/test_workspace_native_connections.py": "6d8b6288577772fb126f4c46fb7bf0c0fa1df6ebba4ae6df113e01492db96892", + "python/tests/test_workspace_native_crash.py": "f5419b10632abb0fbd19712e246851438e0520c76d09b370662db4ae306f9fa7", + "python/tests/test_workspace_native_mysql.py": "eb090deaadc98bfa921bc017b43de780512a6b4c35a909a75fd6b42f19966858", + "python/tests/test_workspace_native_tag_filter.py": "86912660ab6c59706286c4779e1873223ab7569ed772bf85412c2b45e2bdf3a1", + "python/tests/test_workspace_native_tag_integration.py": "3cf4ab9a1b5db849600c2716e9026cfb3d0817389f240d5d9cee9dbfe0b7922d", + "python/tests/test_workspace_native_tag_lookup.py": "57445bfc3e8841bb0541b52181151a985199e599c2e296fe0242908bb0089243", + "python/tests/test_workspace_open_folder.py": "900c8c175f88ad404c6201ebcd7b71ca81ebda7059c3c3656eed5a3a88d989ad", + "python/tests/test_workspace_path_api.py": "f852f8af8b9795c63772800c3ca3cb7203fa0a1b81e0ef562ef848c1e31a06b0", + "python/tests/test_workspace_portability.py": "e907ea424e151e77191f53de2cef625789bf6a85d92c7e8b57a5c24aafe88f61", + "python/tests/test_workspace_portability_app.py": "e4a66a59c5890ab0770ffac6401ac5b202e11081238aa436c09700713f676f7a", + "python/tests/test_workspace_predicates.py": "3e00510d5d3cf76f13bfc679c88635bfb917e1077b5c9bd02649a285da2cf7c6", + "python/tests/test_workspace_project_preferences.py": "52e7a3574d45efee8c89657e46b3a057879ada4ef895fbc5f0c02856b530dbd2", + "python/tests/test_workspace_project_relocation.py": "79882c510136ca6f4c90e81735ed44b8a6e2a61e5c09bc114b04ae4310f0dd89", + "python/tests/test_workspace_project_servers.py": "a9aa45c943854e84c2ffcd7ae17d7b1a2f1f084643881e29678432a1dfd72bb5", + "python/tests/test_workspace_project_validation.py": "572107975e2240615345bca7e6165f1357f148b11ab3a89e163d55f6d53bd1d1", + "python/tests/test_workspace_projection_cache.py": "558a21a3642ee04242252fbc52541f55a81b23bcd912fc2e7ee2f902cdf0ebdb", + "python/tests/test_workspace_projection_objects.py": "0bed3c4a8da2321e37da11e40031530d284f9837ed64ff3b0057193b686a9e17", + "python/tests/test_workspace_projects.py": "32c2dd9c73d2f40ab09522b717d75bb026ba3648f19d5c191b66b9e9fd945b3e", + "python/tests/test_workspace_propagation.py": "d5a7789eebffffe753765886084924073d3ef0fae7ae229415cbe60a5e1e79c6", + "python/tests/test_workspace_protocol_binding.py": "7519a925051a7d86c37ff4003e696c55ed384a83ef3f690dbaebbd98aedc59f6", + "python/tests/test_workspace_protocol_state.py": "67d57fb3c6f37804573dfeb3d94b7c1f74ffef41536344e1e0f3f16f9f04ce08", + "python/tests/test_workspace_qc.py": "ff3875c9233271834a4320d1d23844cf5f0539a6b0973157f03dbf1118c66d39", + "python/tests/test_workspace_recipes.py": "a0aa7499dccae4e1d66b700bcfcb222110568af2785ca2a2a3e46edf1d25da58", + "python/tests/test_workspace_recovery_generation.py": "0bca8f152148f7039b6863c54f4264359783c7b82cb363c51bc4010c257c656a", + "python/tests/test_workspace_recovery_store.py": "520fb79262eb814665db6eb942b38514a147de1a4cf665d5b4fe4d8a12a56ef9", + "python/tests/test_workspace_refresh_cache.py": "e0fcc584585ddd7fd047b092c7fdce7e390d2a48d3a322c94752cf6cb1946e95", + "python/tests/test_workspace_root_boundaries.py": "ed05c71c1c58fac7fe7c8175f983fc849ec7959cd95de064bb17cba357f5ccc2", + "python/tests/test_workspace_scale.py": "f749f206748081a810a41388ff4fedbb18118460eaf347624263eaf21e21d275", + "python/tests/test_workspace_search.py": "2f966a4b4ade0a8e6d9ded8eedb8cea1f6841e56b0ec050acbbb4c40642e7838", + "python/tests/test_workspace_search_presets.py": "5be3998d5c66f44c4dc9463a2d0e951d22ebb7a449c6f181e2a2994ece86dd4e", + "python/tests/test_workspace_service.py": "7fe035916c152aad2df6f41cc6f5c55e8d30cb4168f53c4ab1aa9e171bdd7cfc", + "python/tests/test_workspace_shared_tag_cache_dependencies.py": "9a6586732efdd855886ef80f26523e60c476a51b0de80f33f5d3f2a0338ae5dd", + "python/tests/test_workspace_shared_tag_index.py": "388a786b5e1be76dbdd5daffe649da8fec73045f99e92756c41765674b766b09", + "python/tests/test_workspace_shared_tag_threads.py": "40a756caedd2dbf035a966f5711b610bca98546404aba26d53a6492655468f6e", + "python/tests/test_workspace_shared_vocabulary.py": "9d3a764074be9b89441279aa23eb6c7d7a5a8d077578ea1d282d0a7c9a8e7892", + "python/tests/test_workspace_source_identity.py": "a7bc5ddb5f153aacb23c13eb11b1ca14515ddcd12526567f41e49252931ddf96", + "python/tests/test_workspace_sqlite.py": "863ac4ce766def86d881f13d3e3cf9456a3bf6e649c90ab486e3ab9b68994433", + "python/tests/test_workspace_startup.py": "33aef6fad6f4e3e712e8b25d2738f43705aa9e33cc969bd91f626d7acd4204c2", + "python/tests/test_workspace_startup_registry.py": "2a22b884ff273685c8ba7ec39f796bd0181358f152a7022c2ce31e382320dfb8", + "python/tests/test_workspace_state_generation.py": "9b242c1e9efbcedf724576bd290a99511992744e0fda2f2119de7a8e48f94485", + "python/tests/test_workspace_state_snapshot.py": "07af085d7c1deb6c7ad625af8c52d6a79e48b94a866f12a1f4af4b83dba6b4b0", + "python/tests/test_workspace_storage.py": "e4cb1e8aa0f78b22688f67687675b20066385dba98866d79c11f530cb1f960de", + "python/tests/test_workspace_suggestions.py": "d74f2520953085c8216c12af4186755d11fe39fd81d328f6f58b04d981240489", + "python/tests/test_workspace_tag_exchange.py": "6c4e5109813b93fa9906f34d3108c7d90201b79b9ad108a1a0615bd891d4e3e3", + "python/tests/test_workspace_tag_lifecycle.py": "7ab917a93c3b530dbcca70dac535fccc76dfddb5325bec44480051454d5001d1", + "python/tests/test_workspace_tags.py": "8eb64c890ccf6c6d2556ef50badf337bbe68f157d306ac39bdb05c4137ddbb80", + "python/tests/test_workspace_tree.py": "f137c7fb5a5e9206abde92a866fcae5db8eabde6cb29f8de109b41b1b16d3414", + "python/tests/test_workspace_tree_code.py": "c2b64c14234c31108944ac3bc36a1dfecec2a8e64fe6d17f1f3c131ebb563893", + "python/tests/test_workspace_tree_layouts.py": "215f3660c23b03103ba8ee4ce6ec1fe41e890ab1c51c1ccc26f6d984a53e3046", + "python/tests/test_workspace_tree_pages.py": "3ca10d83d1f7837e8c6c5c12868f8cd9d5c1170237ba9897c039a2c05a730f6c", + "python/tests/test_workspace_updates.py": "bca29343f41d275c8d640f7ae55929d5659bbcdebc667d707cfd20389b0f33dd", + "python/verify_import_progress.py": "167cf6f5935a023d42239be6d3e7fdf8c75d6ee8d8723bc05b2a5b42c66d5865", + "python/verify_sept23_handoffs.py": "e20b9a08dfe47e0b7a1845a934d3023e033e4204d90b60c1ee25f72205d7513c", + "python/verify_workspace_matlab.py": "cfd8b0ce3d5b04d2010d3864504cf64f41a2da00457614a4724f702a6f6eb566", + "python/workspace-mysql-runtime.json": "2474da9de24c81322ba0149536847daf4a716eadd8d2589cdd01c3b519aa41db", + "python/workspace-requirements.txt": "9c5b2fd02d67a11d7b517af100536114368d98b195d17e281e40f42ff4ee8d28", + "python/workspace-runtime.in": "555d294e27881d44a1a6c6730ffb4e12b24497429f30ec425e78cbe6808b2298", + "python/workspace-runtime.lock": "af575b1b6d05b26a6bffad1aac27b6ff00483949412c1bc41191dccd2f1b2708", + "python/workspace-source.json": "aa72758754aaeb4e18046ee18d8e1998d43bd100bf4fda5f9d2dc32e90420441", + "python/workspace_annotation_checkpoint.py": "3ee21f6fe2a1052b0c7d01b3bfc94f958a664bf7c131b076f0272f2692610930", + "python/workspace_annotation_preparation.py": "6d89f8a735c34e6ec3f7f3db291e5d21c1bd8e64a60e7b12563e82dc18eb9f24", + "python/workspace_annotations.py": "7c6bf29aa97bcb7c49c39311ac34f71c2ca744c8dc2125849e22ed97a8b735b1", + "python/workspace_api.py": "8efc55e5fb6079072014c616223872464c0451c6d85bfcb2c61693f9baaed1ff", + "python/workspace_app_routes.py": "29e2b03d11c1c5454fbbe270be2117afd21bcfca0edb3e66320ff01203e11684", + "python/workspace_audit.py": "4b5b033cb59319f4e0277754beaf66eb22788579d8c4452630c18c4e3e7bcc46", + "python/workspace_author_preferences.py": "e36bc7d074c6fbed2f63399538a580adb0f749f1a95024bb39e774671f2ef847", + "python/workspace_backup_scheduler.py": "a7b955dad598ac197ebba8f3e8a988289f61ac2adf47495849f96c55914e1cbf", + "python/workspace_bootstrap.py": "cca734e7ee8faab854204a080c729236339fd45dce2e39b99302c46f62964e07", + "python/workspace_cache_lifecycle.py": "f85876806899228ce4cc79fb3aaee7003bc3e5a55bb51b103db2f17b13d9078a", + "python/workspace_candidate_exports.py": "e5a2421919e08351d2b8367ff773a4019f2433de46ca65cf598781fc55a0b51a", + "python/workspace_catalog_collision.py": "38989ddb1d528289eeacdaa80834bc53a0a61c416bf8a9df5829dc003eb55b28", + "python/workspace_catalog_identity.py": "1a18ce3a8702ba30b60ced08e39ed6a25f26f09255a40c26808818e0c5e707f2", + "python/workspace_curation.py": "9048064f3ab40a20d97e7cde974cdf1541cbcb627f776a8a20edd03a5557fb90", + "python/workspace_curation_vocabulary.py": "2257ff99d2e4543534e7bb4e83d41914b35fb93963631fde021c32943a0f6a0c", + "python/workspace_datastores.py": "afc6139a965bdbfad78643a13ee33ed555339235239c9be938c77b48fd1d7e4a", + "python/workspace_desktop.py": "9bf32c59a9847f5b7231987348fd54ad1f6eec4773323b125ae34d1239632fbb", + "python/workspace_desktop_paths.py": "e32d88c4bf4e41301bd917b8c2cd311e840fd1e45aef28142b8d7f2ece7548e7", + "python/workspace_diff.py": "7f5a806bd9a325a0cbeeeac4bf4e975efb703cca94f727f028353c9e67604798", + "python/workspace_disk_index.py": "bc38a7d0859a0d41edb1fd31b05048211ff4c94a30092003fc1b79b6fa2425a2", + "python/workspace_explorer.py": "13d5cc9e1cf73207b88b011f9a11530049e8ac8b04e0321b8a600d5a3a667d91", + "python/workspace_export_folder.py": "ca98d97d2b693245a10267a103b292c707b394b8593e6eddf08c6bd9d72c9a7b", + "python/workspace_external_tags.py": "6f7cd83c884c6d756dc89f52064692ba46bc40d9caed13660f32213443591a8f", + "python/workspace_folder_browser.py": "efa023840cc73547c1ea653edf077a40979952a7700b6718cd620f316d7d51a0", + "python/workspace_frontend.py": "731954b0e82b927e9fa5cf9a6134b61a23252283ad54e64a8fd307f116931757", + "python/workspace_h5_inbox.py": "5737740344b377b90f7c9d7d09296ff5d66d2cccb558cc287df0283ee3459b02", + "python/workspace_import_check.py": "857cacb94ba3b83454b2aa2c32785930e7b3fcd150c1bca3f25d1cca8c643232", + "python/workspace_import_progress.py": "6b89cd32272a3ae095a1807f0583f317230fe9a726dc54fd1af04c29d6011057", + "python/workspace_installation.py": "e195c160696ac9e2f59a7bd6e79c78e8638dbe3730cdfbb3ebda7296cdff8838", + "python/workspace_launcher.py": "f662aaeaa095b59ecc0459643a7eb924537a8199935fa7b7fd7ade77a24324d1", + "python/workspace_lifecycle.py": "077e4533455420268714bfb2ac79081edf65fbd540a5bc40ced33a6565ee669a", + "python/workspace_mask_refresh.py": "c42948d361060b6a1522255120ed59aa4c76f4cacc6a734e8f8dd1b5277a8546", + "python/workspace_matching_epochs.py": "a2157e20908490c06035a2f765e31ec80f348d5081cd046e1deca58829fe225d", + "python/workspace_matlab.py": "3dd168a224a48a9bfd4f32e14cc3c46c3d0966e95be5ea9ea62f715f9ee31d34", + "python/workspace_matlab_masks.py": "3f0a22f973605d43ce026519a8086b5dc986f0e917c0d1e0e52c39b4aeffdecc", + "python/workspace_matlab_routes.py": "4997dd190e181540ae8217f6aa10e307b2cb4c4f810d17ee92dc8306c54322af", + "python/workspace_metadata_objects.py": "8cb62575cf0fc6198a7e2d4d51e20d7ff14ad6172200bc917d13b3b2b9a372cd", + "python/workspace_migration.py": "06c463bac69caebdb89a8e394e5a5ae0e7c747d07c40a0587a10e83aeb829775", + "python/workspace_mysql_profile.py": "1c06e5a679af3bc8ed842aa6bb6aad38f259bcfa97687c774e21c358f481fed0", + "python/workspace_mysql_runtime.py": "d03c5e41f6fe37a8d514f6c1b90e92769a171c1348ebee62683c395edd4b4224", + "python/workspace_native_mysql.py": "46e2075bd9aa2bf69d2041f06bfdd41305032be2bd8864dfb8c5d0de774e3905", + "python/workspace_native_tag_filter.py": "8cb336a98cf2f487a3bf30db1ddc6ad5db1081018cee394d2690dffa04f8c1bd", + "python/workspace_native_tag_lookup.py": "ae8d7fd3b2f80d56078777b03de4189b648f536ead1ca1225ad6c72a7c59a466", + "python/workspace_paths.py": "c39843552ae94a69fa85aeee558fedea4b0fd7db3151adb039c82283eab733ab", + "python/workspace_portability.py": "582a50eebeabea8f546ac829395e3aef72ab544112147dfb7fa409fd9db39d91", + "python/workspace_predicates.py": "c8b7a4b44a8c051b0216eaaa939f4278ea591c41772a7ec9af8e8899756aa2bd", + "python/workspace_project_database.py": "bfa69cfcef0ba0f566e520e42e07fd31751c410ce7637662b162bae4a55ccbf3", + "python/workspace_project_preferences.py": "418fd4543381a235870ca77a6865c0945fa1a456fe749b7da6997863efd19387", + "python/workspace_project_servers.py": "ff7fb1aa76b0c0afef6726a7c9d21f2ac779f99e0a3c41141e990716c5acba18", + "python/workspace_project_validation.py": "a8478af122534573145b194c9f7a65934e7c83f39b6fbcbd0eb52275effcfd9f", + "python/workspace_projection_cache.py": "89d7a7365de9a64f9b85979e20f0b90b869300c42e62c599c8c436e3bfe88f17", + "python/workspace_projects.py": "bd372ddfe82b46735a0f84c1fa65181d1c8bdc182e42b42b2ff3d80779cc09ce", + "python/workspace_protocol_identity.py": "9a9e3c8426cc9ed58ebd77f4f06e03db2d2287212969ad80e48990fae3e0a986", + "python/workspace_protocol_state.py": "fab53296fc4e06de042c9059c61174e55662de3b20c539667de8679135130c6e", + "python/workspace_qc.py": "ae2fddb5d70edb6a66b803bb44587c8693f3c03dd44ea2b9bcf9874e4175159c", + "python/workspace_recipes.py": "d20f0d8eaf61e0c2d83cb5077ba9671927283f772069e680f2881cd651c52683", + "python/workspace_recording_files.py": "c055b81c518b38da1b632b2ac544f3f2dd277fda4fb4f9d496a41ae9624fa50b", + "python/workspace_recovery_generation.py": "2579fefde5230c735be19f7ab76d05ae20c1ed70a32a731cd31b0b69460d0ce1", + "python/workspace_recovery_store.py": "769f36f82f8a29a2a4c04f8e9accce9fab162d899704d6966b1ae732e6d61804", + "python/workspace_search.py": "b9849cdb0d14ade477df96011c0fc0dadce4e045213e2a206afb82bddcb68a71", + "python/workspace_search_presets.py": "8ab5c84a507eac16be284a106af8cb2cc8d006ee9c715d787ef5b2f481ab0420", + "python/workspace_service.py": "40ba54acf2c5e9983c2e2766179a3d365b30ad1cdc4955410571936f7dfb4954", + "python/workspace_shared_tag_index.py": "b8cbef326a67f096527463dc2dc9490a3a6fdfbed01b2b199ebe369f8c0ead33", + "python/workspace_shared_vocabulary.py": "c196ccc8fcbc1bfb105db7159c286231be2c86ef0bb73317a76f3542b7072590", + "python/workspace_sqlite.py": "49eaf5814a98a808accd03d31f7ef9d652f03c353547570ffa83670daa4393b1", + "python/workspace_startup_registry.py": "3e5fcce7a6df8fbddceead8326943d9327e691cc1e706f1aa08ed02151c187d0", + "python/workspace_state_generation.py": "68e142d6008248c67310462b692b130f0951a87a802187f59d0e6302a78073fc", + "python/workspace_state_snapshot.py": "94cad9f90d27dcae1fbf0d2a7029b3afc60151eace9fc4aad3be41770e5249a3", + "python/workspace_storage.py": "fb5b3b47f08c934999d6c2a678f435e2f475cced24ca54e60f6b5dc2d1650767", + "python/workspace_suggestions.py": "0975ecc4704f218516a7c801f1e057804aa9309bd6c02ebae9eafc6452d6e1d9", + "python/workspace_tag_exchange.py": "e897918039370b98585b61ab3ff58dbfe564224f9b025aafbdf0250c55c07ea4", + "python/workspace_tag_predicates.py": "c2807d6626619ce19ff7b1b83d56a499bd089f79123d71eb92210489368eaa74", + "python/workspace_tree.py": "db25f45e60aa2d0f7091168d983f50db0f353cb6c62e2fba30a571416dcb93ea", + "python/workspace_tree_code.py": "84698df192726094117e2d633e6604200cc618460c4c1e51b927fe0614f5936e", + "python/workspace_tree_layouts.py": "e804f9039acbf86a38ff9b9592a33cabef5f69794c25bcca9e032006a15fa9e0", + "python/workspace_tree_pages.py": "dbaa70e3ffe77be07c01e51ffedecc4d9b04221d08133ae2d1dce9b399e0d332", + "python/workspace_updates.py": "770a6486f9dcc830ae808428b83929a51785b16e10e2f2c8074474d38cd82d4a", + "rieke.py": "33d5c3f181cb58482d6d443b863d014209c06ed35033453811842b7f7f7a2b49", + "workspace-app/package.json": "0005abc7db80a9e86d61d254eb5405061904fa4147736ceb22e4e5482deafefd", + "workspace-app/src/App.jsx": "a5244175e5ca184ad0ba9cf3c91eb20dd33f7295c70061103f4dadada614a922", + "workspace-app/src/WorkspaceNavigation.css": "4c8128ec6230513a5a93686a2708d8709d8bfb6dcae271d278dae48fe021856a", + "workspace-app/src/annotationProfile.js": "20dc38eb4f2e86aff440adc9252e844019183f2b8279422d6a0cd14fd4a94f2b", + "workspace-app/src/annotationReceiptWorkflow.test.js": "9771c0925d8b7a5604631046f3140d30c00c11503b7a2602cafa98a4b40e36d9", + "workspace-app/src/annotationReceipts.js": "609f8b878e03a65c7f7f53d02375d73777ae3bb975e685cfd93299e9d8c167b7", + "workspace-app/src/annotationTags.js": "292b784b215148fb4c8eeb044f7acf8db19d3c6fe4ead9f0c4a5dd465aa89d41", + "workspace-app/src/annotationTags.test.js": "bdde5edfd0656b008566dda3cd0b8ef623fa589969d67427d7df4e42e6453091", + "workspace-app/src/api.js": "9adac79c901fb909e3ae2f00c93a2bad5305abb26ff96f44077b1085c4139c55", + "workspace-app/src/appUpdates.js": "792ab7043c569716d9d8e9088fdc4dcff1931cbd343106c9c0f71081e34376a7", + "workspace-app/src/appUpdates.test.js": "00f5c1d1cbed0f3185c53f332f54d20f51e106f9a1cc1cbc593ca2e7eefbea79", + "workspace-app/src/appUpdatesLifecycle.test.js": "2db1fdff06ded6ffc2d67da1761eeb8fb6a7332efc6502746f21728662452071", + "workspace-app/src/boundedTree.js": "dba203e26cda6933e8bcead18e31409e7f74b6da14054eeaf7de023ca4be78e9", + "workspace-app/src/boundedTree.test.js": "d53b30290e624cd20e3111b90892fd5d0169296e94ec91f5690d4a951ca9eec0", + "workspace-app/src/columnTreeNavigation.js": "78168c3c27ab20942d60150492c0d00946c4ac7fe38ff371842100aea5ee6892", + "workspace-app/src/columnTreeNavigation.test.js": "738ae5b04c000ffc6205c1342d5d71c0d134cf204b7330ede8956ca49f3a197a", + "workspace-app/src/components/AnnotationIndicator.jsx": "27094bdc5b540abe9cefb7e96d7431abb2988b21d09c5c9d44ae8d5e77eefbd8", + "workspace-app/src/components/AnnotationProfile.jsx": "7a1498567883a0661ddbc7f011fbeaf79400b510621092bff6775d3b2851052b", + "workspace-app/src/components/AnnotationTags.css": "5b98288d299cd1a3ca6a3c9565df7698f716c883eebaa8156d1f8781a941633c", + "workspace-app/src/components/AnnotationTags.jsx": "cbbbf6caf02f9adb986d4906f05db3839a29f07094bf11ac71a85712c431d854", + "workspace-app/src/components/AppUpdates.css": "73ccb301ea77a72747d5311bff24e8d09a6272eb106ba9f7378c233ba5247552", + "workspace-app/src/components/AppUpdates.jsx": "e099cc3ca679b596c57cf2fe4767640b5e3c076480aa5c4d95368e482100746e", + "workspace-app/src/components/BrowseFilesButton.jsx": "a64d39292490df41fcd3d68279a9da9d27f941985de9ec739a0ab05b144f006f", + "workspace-app/src/components/CandidateExportPanel.css": "e5bc81b3f742f8d01da663632c9cbc2b8355659105d658bd6281b10e1eee6126", + "workspace-app/src/components/CandidateExportPanel.jsx": "040eeda2357c7fbb7c53623433bd3ff9d3e1c69f2ca8665c31b9d22623480bd7", + "workspace-app/src/components/CellList.css": "0a78471a8c564595482bc0e8e892b367bb273be773baecdd62f86069abcfbe8b", + "workspace-app/src/components/CellQC.css": "0b868c00e767e7523bafb9e5867985d071b8fb231e6dde858bbdc096d56b0db8", + "workspace-app/src/components/CellQC.jsx": "28b872b17920892834ef3e4e8d6642cc7b6a72e0660e598119acde39c03ffd3b", + "workspace-app/src/components/ColumnTree.css": "9b8733010cc0475a5e29b34733106a10ccbe20a1817382d5b68b072c6899f450", + "workspace-app/src/components/ColumnTree.jsx": "1c589ae833fe6c143a165a8f7b1e2e4e5d5e97a4953a245435adce5d170e404b", + "workspace-app/src/components/Common.jsx": "7f602f4b8b21532dae0a6b9eda08dac191a106da2eca7edb617f6ebcb28c1351", + "workspace-app/src/components/DataStores.css": "f745e08bd31946b9abadc939dfda6ad9c79714ea0184d47fdf365271e2380e5e", + "workspace-app/src/components/DataStores.jsx": "d6148e430bf069ca84df112a0702bb8473aa77394adc6e94bc174cc71789db98", + "workspace-app/src/components/DesktopDraftRecovery.jsx": "c92953552716df3fe4c91463888f4c8be77e6ca1a0b88909b805bc5919cc5862", + "workspace-app/src/components/EpochAnalysisInclusion.jsx": "03ace5d560a0545ccc4a1621d481f02ffae6c154b8f97f2d42d2c4da64d7e79d", + "workspace-app/src/components/EpochBrowserChrome.jsx": "d9b0e6ffebe43073beb8467aa066c2694c743369adbd8fa9622b70f1b8524812", + "workspace-app/src/components/EpochBrowserLayout.jsx": "3ffdf64cbd7c5dd0930184519f51702578de700a67fc1b76cfece73f1380473a", + "workspace-app/src/components/EpochConnections.css": "f05cb74270ee2763fb8584a4ed9080b88fd39f74c88a14b8f8cc662fb3c7abc2", + "workspace-app/src/components/EpochConnections.jsx": "22d2a3d50e8b5778de5f3264b01f4477d834e41a3e2901f51f0ce2be525d0e57", + "workspace-app/src/components/EpochDetailHeading.jsx": "378e2f2c0ab79b284f8bdd2c4b5b26633e608ccbf5ced7d0e41f11eca3e60994", + "workspace-app/src/components/EpochInclusionToggle.css": "535519c7f881f9637f7a971a96b13d8493828616b0e1dac9ee28a854360b3041", + "workspace-app/src/components/EpochInclusionToggle.jsx": "7a2aaa8a08370ca9f2658f69f1c2dcc55270f49fe7cf7d858acbfba297c9f1c1", + "workspace-app/src/components/EpochSkimList.jsx": "314a36708443dcfb59da04d7656e2538c0f4035284c5b4721b29c146d27b7b95", + "workspace-app/src/components/EpochTags.css": "107f9535c3196a597917e8310a60cc394320eaeb5a9dca58e3d74cc4045b0876", + "workspace-app/src/components/EpochTags.jsx": "2f2d4be04269e45d82d03df0a7f5d5cb51a4e20330162512e1c9cf0a946c78da", + "workspace-app/src/components/EpochTreePane.jsx": "c161c747a715519092e5b7095472cda91f29d3871f9657a198fc08827881a203", + "workspace-app/src/components/EpochViewer.css": "10c3d7f2b161171e7c9bcb9f589421d0ea39c1a71774555ffbe2bfc42fd7064a", + "workspace-app/src/components/EpochViewer.jsx": "868505b903c22a75920f44a9fbaf069818883d92522fa2fe527aecc14c0aea90", + "workspace-app/src/components/ExportSelectionDialog.css": "e66b8470441ba77bb6016a1e3cd75a456f8e0d2b1af24415a87bf1bcf23fb9db", + "workspace-app/src/components/ExportSelectionDialog.jsx": "465e98b52d5725a343b1089698e493e786b7fb046696b04ac7557a75ae8e4bc0", + "workspace-app/src/components/ExternalTagSync.jsx": "b92c95f6904f9e672f19640f0c235d09cb322aedb7430879a71a927956c05713", + "workspace-app/src/components/FolderBrowserDialog.css": "208acaff373635344e850500c7bf0da42cb588b7521b350c6d9cc8554d9e91b7", + "workspace-app/src/components/FolderBrowserDialog.jsx": "19c600a5dac295327bd9cbcefbad3e6f9944e60782a33e069b49224cbbf99651", + "workspace-app/src/components/FolderPathInput.css": "507ed928e721e5cb326211452e768c24caca610a91d5e95ea9651cb38d90f021", + "workspace-app/src/components/FolderPathInput.jsx": "d4a23e65331c7eb063f2750544864fe8cfddddfa8b9059708e897e25aa0dbdf9", + "workspace-app/src/components/GlobalSearch.css": "93f12d293727faa377046f16a8a7d21b11be8fc7be27eb6c7e02b3cfceb17c51", + "workspace-app/src/components/GlobalSearch.jsx": "fc3884c6260e3a50dd3ad726286ba9b1b7a664946a295aaca9049510641f4e9c", + "workspace-app/src/components/H5Inbox.css": "0282deb5bce72f137980aca75a7b3f502a92b14df9e12e4594283dfe65cd132c", + "workspace-app/src/components/H5Inbox.jsx": "198b771e76a07c9d5348ee3075f31e7a5c043503472e79db8b7afdb8c45bee61", + "workspace-app/src/components/HierarchyTree.css": "50fe5ca506db43074798810af75d521e2e7844455f5d9d18e4300804ab917d61", + "workspace-app/src/components/HierarchyTree.jsx": "cafd448f6773e35d8d20596b82b960aa2b237812dbbfe5f8071e892548c004a8", + "workspace-app/src/components/ImportHistory.css": "fd50cfc26c9e35a6ba50029e7d5aa6d74762e8bd14c6ddd29f6c8fef8eb98e67", + "workspace-app/src/components/ImportHistory.jsx": "0d377697bdfcddc48cb6a34a8c57d21163eb34492a92c95074e167c77073dd55", + "workspace-app/src/components/ImportStatusBar.css": "aa4e4fdc268e3e11dd088d87264368ddc9c3831c1fd084bf7c58fdc7b7c6c598", + "workspace-app/src/components/ImportStatusBar.jsx": "a0058f256ddbb4cda7573e564dfd6d660708ebb8c2470600c0882f308cf041ab", + "workspace-app/src/components/InspectionCellTree.css": "dff8e589b627be899b9031491fd25b4dc51be703fb163635bd87800446d93702", + "workspace-app/src/components/InspectionCellTree.jsx": "5698d31ff446bd7254043c777cd65aa4c3304ed45d2260af2bad84b7c242f3bb", + "workspace-app/src/components/Inspector.css": "d7d86e4a1c78e6884010dfcc19edc35a08c9f212b5b7bd4c0fc2c92bbba8e2e7", + "workspace-app/src/components/Inspector.jsx": "3c67d11f9370786d34fd802278b60e56ab90ab46563914b29b5a45c9f9cd787c", + "workspace-app/src/components/InspectorActions.jsx": "4cfc53a0bf2a3f82a9fa44e0e5a606c2bb946486fb7a35eb93b1960e40bec180", + "workspace-app/src/components/InspectorPolish.css": "9114e1aadc6148996b5720cf28e573270bdadbe1ec8400c5d95b532574f4c246", + "workspace-app/src/components/JointGroupingEditor.jsx": "34662c156a1fc4bc3b5a962cd01b6995fa0651756c0be03a02052072a4fad1b4", + "workspace-app/src/components/LocalExportFolder.jsx": "32c4b01bb7283449d101122d52b3dcdc32f23f60bab13ed3656657cb5f14e324", + "workspace-app/src/components/MasterLog.css": "02fd7220dfaaca4f37003ad9f24bbe0006fb45248e35e9696a78d8583e0291fb", + "workspace-app/src/components/MasterLog.jsx": "35fb9e4619f95bf9b419666d177bc6884edd247f9372f47472dc33353c78d9a9", + "workspace-app/src/components/MatchingEpochs.css": "b3f4be8ec6bb60a98d8618176620bf2775cba2aa16c8eb480e3253542e94b4fc", + "workspace-app/src/components/MatchingEpochs.jsx": "29ffaa736b939f640c9e77001e3d87b72924915e7a7644510a165d71447cdf79", + "workspace-app/src/components/MatlabMaskImport.css": "4ce9eb258f5a7a972819b7e3617c37f9bf6bc682e93ef9d828c25926c986627c", + "workspace-app/src/components/MetadataExplorer.css": "c934d543b4556ba2633059e9e726a4dad178b16afa339ac189bc5e18cf977bac", + "workspace-app/src/components/MetadataExplorer.jsx": "e2f2cd1b1991d3ede3b39222347b156724f4bf75da1c4b06ea4dfc5ac76cb6ee", + "workspace-app/src/components/MetadataPanel.css": "aaa91263881b0fa946886456c30a1a0fd7f8e89c467fc378eeba8233079d4ec6", + "workspace-app/src/components/MetadataPanel.jsx": "40b33eccc1fb6a0dc96fd99a6bd94723205408047b14187a0c6a5051dc872a18", + "workspace-app/src/components/MetadataRefresh.css": "39adef5f82610e4b28146f34dbfac14891e5d5342ed36828ce1a5cb3ef286207", + "workspace-app/src/components/MetadataRefresh.jsx": "003e70dfbe6b4788f41d7e2bec4c2c387142994d9b0fda85919b6b508b597855", + "workspace-app/src/components/MetadataTable.jsx": "357e09938aea2e9eea0fc245a087da74f82d0cd111ae0f5d0b0b10bec3a39f3f", + "workspace-app/src/components/NavigationLoading.css": "e72c85c4783a4962879a03f48188beebcd7af29a2b65b3f41946b43f27f3428f", + "workspace-app/src/components/NavigationLoading.jsx": "42202a49d6db5ca42cad94e590fa73b50c7848ef23d89cd6c5de9ecf5380fe04", + "workspace-app/src/components/NeuronIcon.jsx": "4c8a156735a96855ed1b6d821c7e13ce0da6bdde66386d91e39afa6f8ffb50b3", + "workspace-app/src/components/NewPinnedProtocol.jsx": "963724a9a2c787737a4c507d12c105e8d86e47d85e81c915778c131030f9791c", + "workspace-app/src/components/Overview.css": "6c73bbf9c67a438f683aa246c11f1a3b51b6ae94ea802a3d90f569a69c4c279f", + "workspace-app/src/components/Overview.jsx": "6243f74ed7b69ab4b312d52f9e1b0fe73edccb002cd514cfbc257818b65d4e05", + "workspace-app/src/components/PagedTree.css": "1d98473881ed79693cce57d35e5fd6842d160637469f97b68001e1af4242f976", + "workspace-app/src/components/PagedTree.jsx": "e1fac84aab80a372e9a5b0697ff38450e8a994ea63ad4598e9031093f6f8d105", + "workspace-app/src/components/PaneDivider.jsx": "621b273a7c1f72bd97e3215afa55c611c131dc9284decf54cb094e5d93b3aebc", + "workspace-app/src/components/PredicateBuilder.css": "3bda6621dd2e265c54155513ea48ac7b4325fec2bc07251f019bfe48a53b370e", + "workspace-app/src/components/PredicateBuilder.jsx": "a06e10c872079f6cdf72b243a162cee4426b3fafc7f65720c7b903507d9330ad", + "workspace-app/src/components/PredicateDialog.css": "83504219bd24cfaa332f7364cd60fa4cc385b3bc8e0718206d90cfd538db902f", + "workspace-app/src/components/PredicateDialog.jsx": "480af6a45f4b13ce39837752fbe43a1dbf32fae883faa20a5f8eba226f1749dc", + "workspace-app/src/components/PredicateValueInput.jsx": "8f3881087cf517f130ddace33776798abc5067d8fb94af3813aeb7bcffeb83a4", + "workspace-app/src/components/ProjectClosedNotice.css": "75399b5a1f91b2a47576a7c606efd7341993405f3da0af8b00a40b446b6d37c0", + "workspace-app/src/components/ProjectClosedNotice.jsx": "83acfaba053fd77e31aaebabedfcdd80ba605e66e2ab79dd43f61abb68cd37a0", + "workspace-app/src/components/ProjectFiles.css": "6757af571074a7b5d1f6be99468aa6ebbcd46b768e009897369ab09fbd6551f8", + "workspace-app/src/components/ProjectFiles.jsx": "60c6be5d1ef004d1268b128050f5e036947a72bb840ea8080fedb802b71f3df6", + "workspace-app/src/components/ProjectFolder.css": "e32f571f891c4a0ec300619834c1479e015b512a104a4b7004c28f262e467ee6", + "workspace-app/src/components/ProjectFolder.jsx": "c968611f14e5e5f7448f49dc5fa4de6278b532564bc0f916b4c1ea1414ea541b", + "workspace-app/src/components/ProjectNavigator.css": "7b605ab6236571a86524a513bdf603e8b47ccb7508bae94a93fa3ffc4b0cdcca", + "workspace-app/src/components/ProjectNavigator.jsx": "ccae4f7bd4f2321f569f0f5dec69a49204f5690a51501102cb563c890da78db4", + "workspace-app/src/components/ProjectOnboarding.css": "64f124093f3d920da3c346428acf883c021da249d39c02d89a04b3ee78fc8367", + "workspace-app/src/components/ProjectOnboarding.jsx": "70b8e1e1f688c8bee7f74386c45db2459d819f87ef2c0326bc4696fc0b0edaad", + "workspace-app/src/components/ProjectSetupDialog.css": "74987456de3f0fc3f81a92c297842f1cc60845732e8fc24038c33579a31ea9ce", + "workspace-app/src/components/ProjectSetupDialog.jsx": "9c3fb019fd73b37e9392a3387f946dfdf189a47e1a1a78c0308c8dc1933de603", + "workspace-app/src/components/ProtocolApplyPanel.jsx": "b7c5fc76576a4fa103fe11a63c7cbce43149f85b9100dcac89293e9333f48fc6", + "workspace-app/src/components/ProtocolDiff.css": "2ee5da02d20e185f8f0f6b469b070125afff09f6c91ed13f2dc8ce479f34c6c9", + "workspace-app/src/components/ProtocolDiff.jsx": "0601a64b2e5d2ff428fc70151ff970ad2b7ff020a4516196db40a51c87e07797", + "workspace-app/src/components/ProtocolExportDialog.jsx": "025ecb022d624e99d5cc4666d1945937cb357da0498b688fcb3447095c4908ce", + "workspace-app/src/components/ProtocolExports.css": "1df4feb393d3cf65908b4297240d1a26465d428c4b76d9b2dfc20a31d77f5f0c", + "workspace-app/src/components/ProtocolExports.jsx": "30871b36357e0e22837fc39fd275886fea7e36c6d3a9cac4098fa955acd00198", + "workspace-app/src/components/ProtocolInfographic.css": "b5713e5f8f390ab6f92135b4a7d0a4a024d046117476248b666b5e12127afcab", + "workspace-app/src/components/ProtocolInfographic.jsx": "036c666c24acd7d542190629c7c4a3a19f7d830eedc8d21230e40be387d66a2f", + "workspace-app/src/components/ProtocolSidebar.css": "17acc97de03c883199fae299fe9c5d94dd6dbd16a6a185c2e098c22372aeacfe", + "workspace-app/src/components/ProtocolSidebar.jsx": "465a569ac9d0b08ce050b218a9cf1f505f6a50d4d7ba2dd59856cf590333485e", + "workspace-app/src/components/ProtocolSuggestion.css": "1913b1a507f186a10ad940e607d3fdf6b43aee010943a7950c1c708cd6ecd61b", + "workspace-app/src/components/ProtocolSuggestion.jsx": "1e6cde4228f1667f92811ad6f603342a49e89fd1363368307888e917e8a48d95", + "workspace-app/src/components/ProtocolTagSummary.jsx": "b0948be30deda310ebbc4e4df227b91b69af32e14653d213bfb7d9bb95549c6b", + "workspace-app/src/components/ProtocolViewFilter.css": "4d8d11df6eba13ebc627bd6c200462ea5426aab60124e238fafe9f21879c68db", + "workspace-app/src/components/ProtocolViewFilter.jsx": "8a040f349dd05740cf26430987dea60050ca40e075163d074a89b92a9020e5b2", + "workspace-app/src/components/QueryPresetDialog.jsx": "966211a91c810a28a2f52905cc2745775d18d24197333caec6dbdee6d44695ec", + "workspace-app/src/components/QueryPresetHistory.jsx": "e936645f3fd19c698130df543b57d43b7e561f14de79c6461fac9418acddd381", + "workspace-app/src/components/RecordingSize.jsx": "104efe706dbfd7949c2c5503319fc1c4884cf7172daf59ef9c9e6432fd03159f", + "workspace-app/src/components/ScientificContext.jsx": "02d45b7925421aec4106dcc849aa44180d610659bb7d8631a62279f0e73cbc8e", + "workspace-app/src/components/SearchPresets.css": "76634320a62a0a5224c90facc7d648dcb1119c8588fdbc4d2ce34374a3537a66", + "workspace-app/src/components/SearchPresets.jsx": "a349df170349497ec983590eefa67621dc74fbc0e55ce217baf446251205ef45", + "workspace-app/src/components/SelectionMaskDialog.jsx": "fecf1e9ce7569dc68d8d140617abfb0c826c4b53ef68527357146085d79086b5", + "workspace-app/src/components/SelectionOverview.jsx": "eb1230017552cdefb5933a96925eb8ed5644a268bbcfa630cfbd20f0cf7c40a0", + "workspace-app/src/components/SourcePropagation.css": "b1b66ab2fac3d049f52a04e9c7d36efe6dc90a317a78579453cf7f93d9aef6aa", + "workspace-app/src/components/SourcePropagation.jsx": "00bf1d0be5a13b1efbb7f69aa3c9ea1a95c34c99c0b14442dbc503e0cf160dee", + "workspace-app/src/components/StableContent.css": "f23b6bfdf641260e0af75a822fef5caf0aba5a96ed7542dc58192191b63e7a4c", + "workspace-app/src/components/StableContent.jsx": "4d0a4a157dc649b534332c061949212988e907c6736234dc63ee7318a45f12e5", + "workspace-app/src/components/TagExchange.css": "0ba2ec4ce16a16dee8e76d389572969eb2d7eb0cbbc4903f3af2b758d8547ff9", + "workspace-app/src/components/TagExchangeControls.jsx": "b9e19873c711e68c052f4323038f3bbd6dc8514c7c339fea95afa656f3982f76", + "workspace-app/src/components/TagExchangeDialog.jsx": "9b4cd31adf90ca88682dc19056c342994eae321af1ea6b963169ffa0ff3746e5", + "workspace-app/src/components/TraceViewer.css": "d10504280c216eee76f1cb4653411dfb0162c12c98cf0cd122a1c28446c7df19", + "workspace-app/src/components/TraceViewer.jsx": "00ee6a726cafc7dd8cc830cfcf73f954d9fe725ec3a7363413a547a6920a08eb", + "workspace-app/src/components/TreeBuilder.css": "221a64f02bafd393096ad48fbd3c34389552e1af127484f7626b50f838eddcd8", + "workspace-app/src/components/TreeBuilder.jsx": "cca4dd472e5ecce7349bb0f30d75127502d787766d4bb32b73f62fee2a2ac794", + "workspace-app/src/components/TreePreview.css": "9568ee3b49cef57602d6043f874ab48ed7735893eb0b1668863c707d079bae93", + "workspace-app/src/components/TreePreview.jsx": "fd32bbb0d77dac26117491cd1bbb963d86556b63f5017bfb4f2f6fef2c6b0750", + "workspace-app/src/components/metadataValues.js": "7ce8b253bb1c02dc5b35c79792c1b7fea311f54e854ddb9027cc5e6d08e41906", + "workspace-app/src/components/overviewModel.js": "533dc9377addaf547fd1ae663b7c8229726b7b07c25316cd7f8c3defe4bac766", + "workspace-app/src/components/predicateEditor.js": "4fa96999a5d0ff304af60ce710b8ab6bd823af3d8a53e4e579f147e9db2081c8", + "workspace-app/src/components/predicateState.js": "56ee3c61ae235941344f67f299fa0b42935e482ec68d1d1d7cf9d10c435683c4", + "workspace-app/src/components/traceGeometry.js": "e2c9a9fd769a68a86d87cbfed9aade2a2f601b7d35c0f15e4d955f7b4994206a", + "workspace-app/src/curation-scope.test.js": "03b9d50421dc3ca0fddcf84aa919d869ff8aa12de9d39b3bb31f159b250a3111", + "workspace-app/src/curationSelection.js": "e13d930a935f0f5777205d12986b754fec75f1dd506b1fcebdf8703a384b4009", + "workspace-app/src/curationSelection.test.js": "764f90744d79a4d28f777f9c2361548a12cb9173c815b54855f6d3d5b256a1f8", + "workspace-app/src/desktopDraftSession.js": "e7e3405950fcb1e8d039080591ae8393fb8ecca76c0c650ff991a938ca868de9", + "workspace-app/src/desktopDraftSession.test.js": "9de106d7ec40c8e9241c1dcf7cf6e4503a414c77d14204849109bfdd3274749a", + "workspace-app/src/desktopLifecycle.js": "9fcf5128487dfb59fdb27356d64ae3ba9345776041a72a625d6fd97fe70fb666", + "workspace-app/src/desktopLifecycle.test.js": "153714b002b3dd5c8145a4f719d09855c9a034e21fa8b6053bf0a57c38c85fc3", + "workspace-app/src/epochBrowserSource.js": "c6857102d97fd288634deb1dd61cfde87097e4cf55718de0137925c1bb3ca782", + "workspace-app/src/epochBrowserSource.test.js": "e61ab6d5d4d65b4122ba18b287cfb52bb059bbdc96963b3051d705ce52a7837f", + "workspace-app/src/epochListScroll.js": "6d21ad32bf35ec3d497bc30ae12d687948b6afd00b4e1c6019900ead96b270a6", + "workspace-app/src/epochListScroll.test.js": "95a82ff95404156fe766f7eb46d3af14ad9b0e11e1c7fba87e20ab53a11f1e22", + "workspace-app/src/epochNavigationIntent.js": "4bd629912657d5a8677ddfd1de9b005fbc37b485d935f51a570f44420b838296", + "workspace-app/src/epochNavigationIntent.test.js": "13db4b46eac9baea550fbd7097ed22f707c35a3099b6555a3e2791e096e64a95", + "workspace-app/src/epochSelection.js": "eef553eab8b53ee1f4174fbf960a3f7bd4015dcae2807a44ddd4e497ebebf222", + "workspace-app/src/epochSelection.test.js": "c16dd9e6e30160eff8178c055fbc26aa3d7b74620ae6e2fa8456568e5ccd254d", + "workspace-app/src/epochSkimGroups.js": "06dddaf99cdca361030dae7e80de142f790283ee1329622b7a731d9d6c30ec42", + "workspace-app/src/epochSkimGroups.test.js": "722d25fde0467d94808fe3c28820e102af8d48ba640deb5bb252ea3bf0f7b107", + "workspace-app/src/epochViewerArchitecture.test.js": "9aa453133ac25c1a243102f2b23a2cde4daf0d7ff46c27fb2c471acabf75c91f", + "workspace-app/src/epochViewerRendering.test.js": "6a7875f14460884768f2121cd182e10b5492ab59ac6609fd10089f36f7354408", + "workspace-app/src/explorerScope.js": "ed260ea3caea2aad20336b694f4da892556c0cc2bd50580803759dcc8fc3ab15", + "workspace-app/src/explorerScope.test.js": "a0401aad546e612cdc36b835d4eb00b8e4990076f0af1b0c16c10f1e8e8e7e51", + "workspace-app/src/export-policy.test.js": "9236c64edbfb57aa56ddffc2dc086703205b04c89b889b9b6512f7c4e7624648", + "workspace-app/src/exportFormats.js": "11d0118746055bc0aa7c1a3afa4c11e839444c5ac3ccda9ffb37277b98efc606", + "workspace-app/src/exportFormats.test.js": "fe616c9ba0a18ae9d64c0df80aed7e385358bb717ee51b505b572024ee9080ed", + "workspace-app/src/exportProtocolTargets.js": "3e8dbdf6a2bc507f5402ce8d317ca342535d40403c72a1174aaed9e4071e1525", + "workspace-app/src/exportProtocolTargets.test.js": "ff0c41e9dd019cab6a6ba479ecbc317811d7c2c4cd81843ede2fa862bd290388", + "workspace-app/src/exportReuse.js": "0aba1205e885629cb6e373fd666f66f858b1e0f0df70524fdc38495168ee0650", + "workspace-app/src/exportReuse.test.js": "48c875a98b619112caaef89fb217c62b263c583d3383cccc9e6f294489a6303f", + "workspace-app/src/externalTagMonitor.js": "e980a4466f5e57b2982cca0f307010bec968edda06da78fedca24a35f20ad5a9", + "workspace-app/src/externalTagMonitor.test.js": "e32d55506ef167f245c0eadde6fb698b24ea9998868b26d0b0c4ae0215ad17cc", + "workspace-app/src/folderBrowser.js": "2ffb8fec1c9c72b8d68af7d25223c3ecb58f31cbdfb86ba80a7ff44f14932730", + "workspace-app/src/folderBrowser.test.js": "4b92d9b74350fc08e6b5357381f416f31c14ca31bdc1b1507422029afda9e5ea", + "workspace-app/src/folderPathInputLifecycle.test.js": "b6a10f0bc13603e82540e874fe13dd8c648c6f62be7ea6ddb0b6c1db5a9fade7", + "workspace-app/src/hierarchyTreeState.js": "f3d17947164ab469bfd16c517c8d10f9ca8cd2927420dab436f071c0c2d9a0e2", + "workspace-app/src/hierarchyTreeState.test.js": "4d55ea07487f4682f82715b4afab1c4d14b32091cddeb0080e2c2f56fd604fce", + "workspace-app/src/importProgress.js": "650bbab3b93836b4d315afba9c9577f35942772345b2fa448a64e0a434568f40", + "workspace-app/src/importProgress.test.js": "9dabb78af52e9c73d8e4881be81c8b81e7e6a698894dfc75fe723caca45c8226", + "workspace-app/src/importReadiness.js": "ae89817b7c6a6abfe6fbd20d2a785ac94f27616c1a93a3f981803894f9269531", + "workspace-app/src/importReadiness.test.js": "89114d71e675aad724ae8646916a8a5a4415e391df181ec9830c1b5d5001ecc1", + "workspace-app/src/inspectionCellTree.js": "3e5b9983cc6a727380aad5ecec1e9264301b7f9962fbf426a6bf1ddce3188fab", + "workspace-app/src/inspectionCellTree.test.js": "d60c92efb7ac54227df535880b8e9568ac87d49e11df3f1326407e9033a366d7", + "workspace-app/src/inspectionScope.js": "b752a7ac4a809ac1d433d59a75ace47d0847b2851d77777dbe1a96240c549bc4", + "workspace-app/src/inspectionScope.test.js": "6071c16db65255b65d963470c0e3368c008a8f8eb46752daa4dfc5e4acfeaf5e", + "workspace-app/src/inspectionTreeLifecycle.test.js": "f2567c3c32bb63ee2905db311c610af1fcdcd24105f05332eb8b97694f50d373", + "workspace-app/src/inspectorCurationLifecycle.test.js": "72359c24261254bea423a8b8250fc3c8aef7940ebf0f35d95d4d1d699b7e9412", + "workspace-app/src/inspectorInteraction.js": "9c3b2c69d45314eb41b1fd62ec1b1f0663fca451784db3e4d2b165d6ca6c04a4", + "workspace-app/src/inspectorInteraction.test.js": "34e0e236715e785894c86465910eb1a9f903f902736c875663d2e8bab5ef9c07", + "workspace-app/src/jointGrouping.js": "afe7fcd6d9676a64bf6d96f5ba4f9b7a4fe27416fe0523114d154a1e67edb4ec", + "workspace-app/src/jointGrouping.test.js": "508af81429c764688db6e549e28ace293b82d29bcf2c8a12affc5e880d128263", + "workspace-app/src/loadingNotice.js": "37e7ac79febafd4b07a54beeebd8b11e2de143e6c7ab6dab066f65175233dd9a", + "workspace-app/src/loadingNotice.test.js": "ed96cc0f78b5e72f8249eacaac784a86400a5e582dcbd1830279937eacdd1bcd", + "workspace-app/src/main.jsx": "71e69d3115df4c686a931737c07357f1e85123c5719c903175a4e032be7536f6", + "workspace-app/src/metadataRefresh.js": "ca29104e42a02cc99a23598958582bca509fc2dd7cb229d124d99a0e54239314", + "workspace-app/src/metadataRefresh.test.js": "85a68db32a16a3e67666a9c353c45f4e3761ddae2e6de8bf4690af25c2a90be5", + "workspace-app/src/metadataSearch.js": "766b7a7d12fcf827a0761a0ff367d34748a3d093275f819f7c7ae7103f637474", + "workspace-app/src/metadataSearch.test.js": "d74db36dc9d27b39f3e90fd71b6a34f51f90a368b4e69e8dfc29bbd31f9168c8", + "workspace-app/src/metadataValues.test.js": "4baf4f36cd38e3e8849d725225b52ef7cb194545ad780011c8b3ab3a98147c14", + "workspace-app/src/ordering.js": "3fe5ca26a4eedff0c101e513fdf5f5973554afaadddda2f75fab6476d3e5064e", + "workspace-app/src/ordering.test.js": "a97c50b8a3c69719ee0243b4fcc1dd74ca423bffa74a9104fcbd60c7f36facb7", + "workspace-app/src/overviewModel.test.js": "cf8ee3fc618de607bf4bdbdd0ee76118471015ae8d5e0a2aeaa1aacc224bdb5a", + "workspace-app/src/pagedTreeLifecycle.test.js": "ca49e829a3d84889542c1c72c9b251119a569ebe7f12011e4ca6b416d12d2eb4", + "workspace-app/src/pagedTreeRequest.js": "e6ccfb4db1224452719fd6ecab59e3e05697c057e19bf34552104de28593b887", + "workspace-app/src/pagedTreeRequest.test.js": "84e0a69b7e780eb927676d2e2a17ef83a010eb4038797a72531771b545101e28", + "workspace-app/src/pointerDrag.js": "c1062622121f82cdd4d20847b990d1657708e160008c0741c9b41855d8b7d2e0", + "workspace-app/src/pointerDrag.test.js": "261ad37352c817b0e44723c7db4f0c7d1612e1b65c66e3acf4961eac267faf83", + "workspace-app/src/predicateEditor.test.js": "98ad8f7e803eb31b460645891e696b4e1cbdf97e0527762374f4304e171b15fa", + "workspace-app/src/predicateFieldPresentation.js": "95c8215c786e14ed0b96b807df2a41a09948c3133fc3004dabbddd77728693ec", + "workspace-app/src/predicateFieldPresentation.test.js": "1d4695da51af48fa8676d5de98e2ff00e6960618a4f106fe906f48da6c36f8d2", + "workspace-app/src/predicateIdentity.js": "59cf1abd3454c8c3382cb35ab7845d96f4d338bdbbd43f0efb6723722b6c75c1", + "workspace-app/src/predicateIdentity.test.js": "98369a6618d0bb2928a63d3ac4e304f82efe713d1191d5f36f981daad4f55f5f", + "workspace-app/src/predicateState.test.js": "0a29a48443fce3d729d5ac8db161623095e0b2968544f2d9aabbc338ccfd3922", + "workspace-app/src/predicateValueSuggestions.js": "24afa38099571f416d1e54771ee0fa60450e24fdcf295245e9885dae14a95d74", + "workspace-app/src/predicateValueSuggestions.test.js": "28ca7ca5ad5d06e86d48d30666215d01534544c5198aeab4d92dbb0a72e86b1b", + "workspace-app/src/projectNavigation.js": "4a53606229e8ed0787144a018f82910da5ca27e73cacad7341e350baaf3053de", + "workspace-app/src/projectNavigation.test.js": "50f6c9743e491740ac3099ef21ac9d71b76dddbbb9afe165edb357c0f4d5af0c", + "workspace-app/src/projectPreferences.js": "c8e35df6c18d80895fe7e12d86dd3827e59670d4e7868732e65b85050482a08e", + "workspace-app/src/projectPreferences.test.js": "99216a435e9963ab8ff1a4d75ebf2ea5cab5bc9b56fa61205898a70462263f67", + "workspace-app/src/projectSearchPresets.js": "d0ad7e9a9ee5bf433fb38c9fdc6df737751993ed30eedf2cde37250df2de8c49", + "workspace-app/src/projectSearchPresets.test.js": "d0116a52e5c694e8da5576f7fdc0a76d056826fa5555430b127f94549cfe22f8", + "workspace-app/src/projectTransfer.js": "f49fe91f3850fa7b36250eff35d2d39d156aafb67ddfa14b5fb8cca86aa60432", + "workspace-app/src/projectTransfer.test.js": "796b09a088c51a5e65753ab66fb9151625349a7688e9a38d6fc75b4f651a8bef", + "workspace-app/src/protocolOverviewModel.js": "56bb36a40dc42c15c4bf8f0a1ee50521ac513dac3e3a614ac4c1a3531a21afa7", + "workspace-app/src/protocolOverviewModel.test.js": "980162b6e21d70d178ead87159318f22d9412a06d4694f6dc2b5c386eedc84a9", + "workspace-app/src/protocolSuggestions.js": "bf5674469ca030db7721182f0e5a2858ef1e156f6e7e508dd00ebfaec054894e", + "workspace-app/src/protocolSuggestions.test.js": "1fdb6bda2f131a3db6fce1a439e0b294e9d5c1f60645534aa60676f4893e26c7", + "workspace-app/src/protocolViewFilter.js": "691e89aa4a444629f8415eb35c0a920001fb02f1b3b9cfd98729602697f11962", + "workspace-app/src/protocolViewFilter.test.js": "4a4b7245382e83a75cbfee7591f9d7f21c8ca0a714fe533eff8a462a7f3236f6", + "workspace-app/src/recordingIdentity.js": "14171269f759d95e2050b2a433957dca930106efc7cbb5d6de4ede5c472f1e32", + "workspace-app/src/resourceCache.js": "17ca8c7c8a45768430d967e3ef53c358fa91ff37f25666734de1fa8df760cbad", + "workspace-app/src/resourceCache.test.js": "c79a1eebec4c49cbaee89e2b7ab969fe693efa95b9522547b8bce464cb7b71d7", + "workspace-app/src/resourceRequest.js": "7f7ed9af2de01b03cff6687e8221f129a91ffd5ea7230cf3c9d6859d1dc33e76", + "workspace-app/src/resourceRequest.test.js": "e8cc14c6a9c3cb0238eb478852b6f200a05b493cae1cd6ec5c91cb6b3ee41c08", + "workspace-app/src/searchInclusion.js": "ac63f91061362bae667791420f611ae52c89327f1f5e6ec692838b011ad97aa6", + "workspace-app/src/searchInclusion.test.js": "e3e12732312841ec822c8d19772e2c348b6441bcd31eb4842fc7c5c0be8d1439", + "workspace-app/src/searchPresets.js": "00837ffb304a76e41352d7137a3b97164d27614236159cc8b3f3f02c78d23dcc", + "workspace-app/src/searchPresets.test.js": "130cf9c2613f368f56582f46502f524bc796a8ef63830c85b759697e170c2c05", + "workspace-app/src/styles.css": "5c74ca2166464b975cbdafd6e3ed3a11d918eae7b929be0d8a8a431b5d247fb0", + "workspace-app/src/tagExchange.js": "8192d55f54542717960dd5443cb2cbac24728092dc802257adf2c2dfbb747a69", + "workspace-app/src/tagExchange.test.js": "2afa7da8fa2b84c65602060e411af73e1c68f24b9d1d3bd2169da757613a9f34", + "workspace-app/src/test-support/inspectionTreeHarness.js": "58c038bc97337a92de3fb0ae64a9fb608adbba634a6dce48852d9190e0de32e7", + "workspace-app/src/test-support/inspectorHarness.js": "09a1905ac6e3c5899d89a5a2b1d35b5804fecddb42a83c4b4b0b6bd40c13f9c7", + "workspace-app/src/test-support/pagedTreeHarness.js": "3c714ac9cf9dcf71c516c80cfd28326bde9a7f503925642f243ec68cb6548180", + "workspace-app/src/test-support/workflowHarness.js": "836e9fdc3411d7dca9e3585058650592e79c4dd7b2ac9135c2d49aea91ba6de7", + "workspace-app/src/traceGeometry.test.js": "afa9d853be58ceb78b0bd5593ffc983ce7365318e9145fdf2bb1c5940092d76f", + "workspace-app/src/treeBranchPresentation.js": "da35be6063e256faf1c89f9b2a93fcd1834ac7fee26d9c3a00ba517ae7f841c0", + "workspace-app/src/treeBranchPresentation.test.js": "0406f370dff4f4f7673d0f70c36a7a2ede68fda878817da455db4a4808bd8bde", + "workspace-app/src/treeFieldPresentation.js": "f64652cdcfafb7b526f5fa3646ed55bbeeea05540cef6bd8e2ca5272544851d5", + "workspace-app/src/treeFieldPresentation.test.js": "b3103dfb4fbeaa0bf84eb523ae0de1d9421880dde7443397a7487754e57aab81", + "workspace-app/src/treeLayoutPersistence.js": "84e5ddb9bdfb5bbc53072a1de7f1816dcdeaa415c81b4dec5001e1d7864ab24f", + "workspace-app/src/treeLayoutPersistence.test.js": "9a2c719ca3f0410263ab6c28dd3aa91870e05a4136e789ca9dd3c76efbbc5afc", + "workspace-app/src/uploadRecording.js": "f7587bc910536b4796d3206d27a2cfe9f31815a057f3c7e28375f117a22584bf", + "workspace-app/src/uploadRecording.test.js": "7a5d8cd30f1a7a98e92aaec7e1750e786e776ec23e5a6552f684397c8744a69a", + "workspace-app/src/useAnnotationReceipts.js": "761e02d9f9c523880193ffbc16c661475b87b474a1cacd99d8f9349964b10c49", + "workspace-app/src/useDesktopDraft.js": "0dcdae9aa69cf869166b2673633f74d568a3b67d32995d607a8658636d1ccde7", + "workspace-app/src/useEpochBrowserPage.js": "3e61a3bdb70371a53180463646fece3dca9ede345502932e8e5e787472de30ec", + "workspace-app/src/useImportMonitor.js": "caa732e28c72921dbe5609337e71d366e513c465c61cf63bb07b02bdc929fb4c", + "workspace-app/src/useImportQueue.js": "9af2c96cdd5eb30e3a6fb768634c79082b0804851cc7ee15028b8296e80e8071", + "workspace-app/src/useProjectPreference.js": "c920a9fed4d829a5a768aab1f595b9e3f8ce2dd9df02182deeaa9d4d82ea4e1e", + "workspace-app/src/useProtocolTreeLayout.js": "edb12b76a4349ae940ed8e38ab52a6c9062ea867045889e1b612dc9baeef2c0d", + "workspace-app/src/useWorkspaceChanges.js": "cfb71618d364764fd6fc9060a5d8e3a5550fb61de81562cf25bd942c2baa4670", + "workspace-app/src/useWorkspaceNavigation.js": "19d42b45a2456dca6410c357a9a266dcc90e1dc983dc031d24a4ef0d986d9378", + "workspace-app/src/workflowResponsiveness.test.js": "2b4d5af0ca966e399d16a9af37a38a63f794daf9dc4c25e5d8e6925c126488be", + "workspace-app/src/workspaceNavigation.js": "cc44e94ca7a4ed4b2b5735d1b737509b8ce02acbe23f972852d60400c0d9581d", + "workspace-app/src/workspaceNavigation.test.js": "713433cb63af4f325df982405edd6bddb50f66aec2a53277529ff7d4092fa0b4" + }, + "total_bytes": 5395127, + "scope": "Python sources/config/tests, frontend audit source/package metadata, retinanalysis src, three benchmark scripts; excludes runtime binaries/databases/node_modules/bytecode.", + "unchanged_after_500_and_before_100000": true, + "unchanged_after_both_scales": true, + "validated_receipts": [ + "native-tag-sequence-500.json", + "native-tag-sequence-100000.json" + ] +} diff --git a/docs/dev/scale-audit-2026-09-29/native_generation_authority_probe.py b/docs/dev/scale-audit-2026-09-29/native_generation_authority_probe.py new file mode 100644 index 0000000..8f2845d --- /dev/null +++ b/docs/dev/scale-audit-2026-09-29/native_generation_authority_probe.py @@ -0,0 +1,283 @@ +"""Independent native checks of the production generation authority. + +Only creates its own disposable project; intentionally kills only the verified +owned MySQL child. Minimal source tables exercise the real production triggers. +This does not certify DataJoint/service integration or artifact restore. +""" +import argparse +from dataclasses import asdict +import hashlib +import json +from pathlib import Path +import shutil +import struct +import tempfile +import threading +import time +import traceback +import uuid + +import pymysql +from workspace_projects import create_project +from workspace_native_mysql import ensure_native_database, stop_native_database, connection_parameters, _owned_process +import workspace_state_generation as generation + + +class Connection: + """Only adapt cursor/result spelling; no generation behavior is emulated.""" + def __init__(self, project): + self.project=project;self.in_transaction=False;self.reconnect() + def reconnect(self): + self._conn=pymysql.connect(**connection_parameters(self.project),autocommit=True) + def query(self,sql,args=(),as_dict=False,reconnect=False): + cursor=self._conn.cursor(pymysql.cursors.DictCursor if as_dict else pymysql.cursors.Cursor) + cursor.execute(sql,args);return cursor + def close(self): + self._conn.close() + + +def main(): + ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--output',type=Path,required=True);args=ap.parse_args() + if args.output.exists():ap.error('Choose an unused output file') + root=Path(tempfile.mkdtemp(prefix='rieke-native-authority-'));project=None;connections=[] + before_hash=hashlib.sha256(Path(generation.__file__).read_bytes()).hexdigest() + report={'scope':'Production authority + native SQL; minimal source table adapter; not service/restore certification', + 'source_sha256_before':before_hash,'probe_sha256':hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + 'cases':[],'release_ready':False} + def check(name,condition,**extra): + row={'name':name,'passed':bool(condition),**extra};report['cases'].append(row);print(json.dumps(row,default=str),flush=True) + if not condition:raise AssertionError(name) + try: + project=Path(create_project(root/'projects','Native authority probe')['path']);runtime=ensure_native_database(project) + connection=Connection(project);other=Connection(project);connections=[connection,other] + sql=lambda statement,params=():connection.query(statement,params).fetchall() + external=lambda statement,params=():other.query(statement,params).fetchall() + project_id=str(uuid.UUID(int=1));project_two=str(uuid.UUID(int=2));protocol=str(uuid.UUID(int=3));protocol_two=str(uuid.UUID(int=4)) + epoch=str(uuid.UUID(int=5));epoch_two=str(uuid.UUID(int=6));profile=str(uuid.UUID(int=7));profile_two=str(uuid.UUID(int=8)) + report['mysql_version']=sql('SELECT VERSION()')[0][0] + sql('CREATE DATABASE IF NOT EXISTS recording_workspace') + definitions={ + 'curation':'project_uuid VARCHAR(36),protocol_uuid VARCHAR(36),epoch_uuid VARCHAR(36),tags JSON,revision INT UNSIGNED,PRIMARY KEY(project_uuid,protocol_uuid,epoch_uuid)', + 'shared_annotation':'project_uuid VARCHAR(36),target_kind VARCHAR(16),target_uuid VARCHAR(36),profile_uuid VARCHAR(36),tags JSON,author_name VARCHAR(120),revision INT UNSIGNED,PRIMARY KEY(project_uuid,target_kind,target_uuid,profile_uuid)', + 'annotation_profile':'project_uuid VARCHAR(36),profile_uuid VARCHAR(36),display_name VARCHAR(120),PRIMARY KEY(project_uuid,profile_uuid)', + } + for table,definition in definitions.items():sql(f'CREATE TABLE recording_workspace.{table} ({definition}) ENGINE=InnoDB') + authority=generation.bootstrap(connection,project_id);other_authority=generation.bootstrap(other,project_id) + check('bootstrap',authority.ready and other_authority.ready,reason=authority.reason) + external("SELECT GET_LOCK('rieke_state_generation_v1',0)") + def release_bootstrap(): + time.sleep(.1);external("SELECT RELEASE_LOCK('rieke_state_generation_v1')") + releaser=threading.Thread(target=release_bootstrap,daemon=True);releaser.start();started=time.perf_counter() + try:contended=generation.bootstrap(connection,project_id) + finally:releaser.join(timeout=5) + check('concurrent_bootstrap_waits_and_recovers',contended.ready and time.perf_counter()-started>=.08,reason=contended.reason) + def token(ident=protocol): + value=authority.token(ident) + if value is None:raise AssertionError('Authority unavailable: '+str(authority.reason)) + return value + def head(value):return (value.protocol_epoch,value.protocol_generation) + initial=token();check('second_connection_agrees_on_scope',head(initial)==head(other_authority.token(protocol))) + external('INSERT INTO recording_workspace.curation VALUES (%s,%s,%s,%s,1)',(project_id,protocol,epoch,json.dumps(['QC','qc','é','e\u0301','first']))) + inserted=token();check('curation_insert',head(initial)!=head(inserted)) + external('UPDATE recording_workspace.curation SET tags=%s',(json.dumps(['QC','qc','é','e\u0301','other']),)) + updated=token();check('same_revision_external_update',head(inserted)!=head(updated) and sql('SELECT revision FROM recording_workspace.curation')==((1,),)) + external('REPLACE INTO recording_workspace.curation VALUES (%s,%s,%s,%s,1)',(project_id,protocol,epoch,json.dumps(['replacement']))) + replaced=token();check('replace_delete_and_insert',replaced.protocol_generation==updated.protocol_generation+2) + old_two=token(protocol_two) + external('UPDATE recording_workspace.curation SET protocol_uuid=%s',(protocol_two,)) + moved=token();new_two=token(protocol_two);check('protocol_key_move_invalidates_both',head(moved)!=head(replaced) and head(old_two)!=head(new_two)) + third=generation.bootstrap(other,project_two);old_project=token(protocol_two);new_project=third.token(protocol_two) + external('UPDATE recording_workspace.curation SET project_uuid=%s',(project_two,)) + check('project_key_move_invalidates_both',head(old_project)!=head(token(protocol_two)) and head(new_project)!=head(third.token(protocol_two))) + external('UPDATE recording_workspace.curation SET project_uuid=%s,protocol_uuid=%s',(project_id,protocol)) + before=token();rows=sql('SELECT * FROM recording_workspace.curation');other._conn.begin() + external('UPDATE recording_workspace.curation SET tags=%s',(json.dumps(['rolled back']),)) + during=token();other._conn.rollback() + check('rollback_preserves_visible_counter_and_rows',before==during==token() and rows==sql('SELECT * FROM recording_workspace.curation')) + before=token();external('DELETE FROM recording_workspace.curation');check('delete_last_row',head(before)!=head(token())) + external('INSERT INTO recording_workspace.curation VALUES (%s,%s,%s,%s,1)',(project_id,protocol,epoch,json.dumps(['restored']))) + # Shared/profile updates and old-key tombstones share project commit order. + before=token();external('INSERT INTO recording_workspace.annotation_profile VALUES (%s,%s,%s)',(project_id,profile,'same name')) + after=token();check('profile_insert',before.shared_generation