Skip to content

fix: give the isolated soak config the theme packs the launcher needs to import - #86

Merged
test1card merged 19 commits into
masterfrom
fix/soak-isolated-config-theme-packs
Aug 20, 2026
Merged

test1card merged 19 commits into
masterfrom
fix/soak-isolated-config-theme-packs

Conversation

@test1card

Copy link
Copy Markdown
Owner

What this is for

The short endurance run is the evidence the laboratory week rests on, and it stops before it measures anything. This makes it start.

The measurement

On Ubuntu 22.04.5, in a worktree cut from a native Linux clone, the short soak:

  • reaches the runner phase and writes seven evidence files;
  • passes the exact-six integration gate (exit_code 0, status PASS);
  • then fails with _RunnerFoundationError: source stack did not reach the exact four-role startup cut.

log-launcher.txt names the real cause: cryodaq.gui.theme resolves a theme at module import, and the default pack is not found.

Why the pack is missing, which is not what it looks like

The pack is not missing from the tree. It is tracked, and git archive carries it into the sealed snapshot. It is missing from where the child is told to look.

_source_environment sets CRYODAQ_ROOT to the isolated root. get_config_dir() is get_project_root() / "config". That isolated config/ holds only the curated passive set — _ISOLATED_TRACKED_CONFIG_FILES plus _ISOLATED_STATIC_CONFIGS — and there is no themes/ among them.

Measured both ways with evidence/tools/rootprobe.sh in the workspace repository:

  • A. CRYODAQ_ROOT at a directory without config/ reproduces the recorded traceback exactly, exit 1.
  • B. CRYODAQ_ROOT at the application tree with CRYODAQ_STATE_ROOT at the isolated directory imports cleanly, exit 0.

Why the copy rather than arrangement B

Arrangement B is the split src/cryodaq/paths.py documents and it works. It also hands the child the whole real configuration directory, which is exactly what the isolated root exists to prevent. The curated set is a safety property, not an accident.

Theme packs carry no hardware authority. They are colours. Copying them into the isolated set restores the import without giving the run anything it could act on.

What the change is

A new _ISOLATED_TRACKED_CONFIG_DIRS = ("themes",), copied file by file into the isolated config, and refused by name when the source has no themes directory or when it is empty. Left to the launcher, the same condition arrives as "source stack did not reach the exact four-role startup cut" — a symptom without its subject — and tracing that back cost a full measurement round.

Control

Run by reverting production to master, not by reasoning about it. With scripts/soak_mock_stack_runner.py restored to master, test_the_isolated_config_carries_the_theme_pack_the_launcher_resolves_at_import fails because the themes directory is absent, not because a symbol is missing:

E       assert False
E        +  where False = is_dir()
E        +    where is_dir = WindowsPath('.../themes').is_dir

With the change: tests/scripts/test_soak_mock_fixture.py reports 11 passed, 12 skipped; ruff check src/ tests/ clean; the workflow-exact format check clean over 702 changed files.

What this does not do

It does not change the refusal itself. resolve_theme() stopping the program over a colour file is pinned by tests/gui/test_theme_loader.py::test_missing_default_pack_raises, and a tree with no config/ has no safety configuration either, so stopping is defensible. Whether it should stop is a behaviour decision and belongs to the owner.

It also does not prove the endurance run completes. It removes the first barrier; what the run finds after it is the next measurement.


Written with assistance from Claude (Anthropic).

… to import

The short endurance run stops before it measures anything. Measured on Ubuntu
22.04.5 in a worktree cut from a native Linux clone: the run reaches the runner
phase, writes seven evidence files, passes the exact-six integration gate, and
then fails with "source stack did not reach the exact four-role startup cut".
The launcher log names the real cause: cryodaq.gui.theme resolves a theme at
module import, and the default pack is not found.

The pack is not missing from the tree. It is tracked, and git archive carries it
into the sealed snapshot. It is missing from where the child is told to look:
_source_environment sets CRYODAQ_ROOT to the ISOLATED root, get_config_dir is
that root plus config, and the isolated config holds only the curated passive
set, which has no themes.

The curated set exists so the endurance run cannot reach real hardware
configuration. Theme packs carry no hardware authority -- they are colours -- so
copying them in does not weaken that. The alternative, pointing CRYODAQ_ROOT at
the application tree and relocating only the writable state with
CRYODAQ_STATE_ROOT, also imports cleanly and was measured to do so, but it hands
the child the whole real config directory, which is the thing the isolated root
exists to prevent.

The directory copy is refused by name when the source has no themes directory or
when it is empty. Left to the launcher, the same condition arrives as "source
stack did not reach the exact four-role startup cut", which names a symptom
without its subject, and tracing that back cost a full measurement round.

Control, run by reverting production to master rather than by reasoning: the new
presence test fails there because the themes directory is absent, not because a
symbol is missing.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

…ely adding it

Measured, not predicted. Running the short soak at the previous head of this
branch on Ubuntu 22.04.5 moved the failure EARLIER rather than removing it:

  phase runner, state FAIL, reason "passive source fixture topology is not exact"

and only summary.json was written, where the unfixed run had reached the runner
phase and written seven files. Adding a directory to the isolated configuration
broke the fixture seal, which walks an exact topology: a fixed set of files plus
one EMPTY directory. That is the whole point of the seal, so the seal is what
had to learn about the new directory.

The theme packs are now sealed the way the files are -- identity, no links,
exact mode, content hashed -- and the per-file check is a nested function so both
loops run the same code rather than a copy of it. The directory is created with
mode 0o700 and its files with 0o600, because the caller's permission sweep only
reaches the top level and the seal demands those modes.

A populated tracked directory is also checked for emptiness and re-listed after
sealing, so a file appearing between the listing and the hash is a refusal
rather than an unsealed byte. A directory the launcher must read at import is
the last place an unsealed byte belongs.

tests/scripts: 132 passed, 94 skipped. The next measurement is the same run at
this head, which is what decides whether the barrier is actually behind us.
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 93dd5259f4f06a14b6dc53299c64e2241f8f2e90. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@test1card

Copy link
Copy Markdown
Owner Author

Measured end to end in the real runner, on the laboratory machine

Ubuntu 22.04.5, worktrees cut from the native Linux clone.

This branch and #87 are sequential, and both are needed. Running the short soak at #87's head alone — aa317df2db, without the theme fix — the exact-six stage now passes (exact-six-result.json, exit_code 0, status PASS) and the run then fails at exactly the barrier this branch removes:

RuntimeError: Default theme pack invalid: theme pack 'warm_stone' is unavailable
  src/cryodaq/gui/_theme_loader.py:170 in resolve_theme
  src/cryodaq/gui/theme.py:20 ACTIVE_THEME_ID, _pack = resolve_theme()

Merging both branches locally — never pushed, evidence/tools/combine_and_soak.sh in the workspace repository — and running the same soak, the launcher starts:

Loaded 12/12 bundled fonts
Первичная настройка отложена: launcher запущен в --tray режиме
ZMQ bridge subprocess started (PID=691, restart_count=1)
Запуск engine как подпроцесса...
Engine запущен, PID=694; stderr capture active

So the theme barrier is gone and the process gets as far as constructing the engine.

What stops it next, and the gap that hides why

One second later:

CRITICAL Launcher construction failed; phase=engine exception=RuntimeError
CRITICAL Launcher retained all construction owners in HOLD after phase engine.

The engine started, was assigned a process id, and did not reach readiness. _wait_engine_ready raises RuntimeError("live engine child exited before exact readiness") for exactly this, so the engine died before writing its receipt.

Its reason is not in the evidence. The launcher forwards engine stderr to engine.stderr.log under the log directory, which lives inside the isolated state root — the runner's temporary directory, removed when the run ends. The evidence bundle carries six files and none of them is that log:

exact-six-result.json  log-launcher.txt  log_capture.json
manifest.json          prerequisites.json  summary.json

So the run reports a condition without its subject, which is the shape this project already treats as a defect in its own right. The next change is to publish engine.stderr.log into the evidence beside log-launcher.txt, redacted and bounded the same way, and it is a precondition for saying anything further about the engine phase rather than guessing at it.

Not started here — this branch stays about the theme packs.

Review found a break this branch introduced and the branch's own tests could not
see. The seal now carries the theme directory and its packs, so the payload holds
27 entries where the ledger's validator still required exactly 14 and rejected
every path under themes. The cost is worse than a red test: every soak run --
short, twelve-hour or seventy-two-hour, all sealing through the same ledger --
would run its full duration, write all its evidence, and then be destroyed at the
last gate by an error naming neither themes nor the manifest.

The topology is now checked by SHAPE rather than by a fixed entry count. The
count would otherwise have to know how many theme packs the tracked tree happens
to hold, which is exactly the coupling that drifted. Top-level files must be the
expected set, both sealed directories must be present as directory entries, and
every remaining path must be a file one level inside a sealed directory, with at
least one such file.

The second finding was the more important one: every manifest test hand-builds
the payload, so the runner's seal and the ledger's validator were free to drift
and nothing connected them. Two tests close that. One feeds a payload the runner
ACTUALLY produced through the validator the ledger ACTUALLY calls. The other
asserts the validator still REFUSES a fixture with no theme packs, so teaching it
a new shape did not teach it to accept a missing one -- the launcher resolves a
theme at import, so a fixture without the packs cannot start the program.

tests/scripts: 133 passed, 95 skipped.
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 092f5b34481ccd299d2128c437c2f3f7d3cae700. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@test1card

Copy link
Copy Markdown
Owner Author

Both findings are closed at 092f5b3448, and the first one was a real break this branch introduced.

The acceptance validator now knows the topology this branch creates. The seal carries the theme directory and its packs, so the payload holds 27 entries where _validate_source_fixture still required exactly 14 and rejected every path under themes/. The cost was worse than a red test: every soak run — short, twelve-hour or seventy-two-hour, all sealing through the same ledger — would have run its full duration, written all its evidence, and then been destroyed at the last gate by an error naming neither themes nor the manifest.

The topology is checked by shape now, not by a fixed entry count. The count would otherwise have to know how many theme packs the tracked tree happens to hold, which is exactly the coupling that drifted. Top-level files must be the expected set; both sealed directories must appear as directory entries; every remaining path must be a file one level inside a sealed directory; and there must be at least one such file.

The second finding was the more important one, and it is the reason the first shipped invisible: every manifest test hand-builds the payload, so the runner's seal and the ledger's validator were free to drift and nothing connected them. Two tests close that:

  • one feeds a payload the runner actually produced through the validator the ledger actually calls;
  • the other asserts the validator still refuses a fixture with no theme packs, so teaching it a new shape did not teach it to accept a missing one — the launcher resolves a theme at import, so a fixture without the packs cannot start the program at all.

Measured: tests/scripts 133 passed, 95 skipped; the old hand-built topology is rejected, the real seal payload validates clean. ruff check src/ tests/ clean and the workflow-exact format check clean.

Thank you for the read — neither of my own runs reached the sealing stage, so nothing I measured could have caught this.

The second review round found that my own repair opened two holes, and it was
right about both.

The membership helper treated BOTH sealed directories alike, so a single
experiment_templates/anything entry satisfied the theme-presence check while the
payload carried no theme pack at all. The test that claimed to cover it passed
only because its hand-built payload had no members of either kind -- a control
passing for the wrong reason, which is the exact shape the round before this was
about. Membership now belongs to the populated directory only, and the runner
seals experiment_templates EMPTY, so a member of it in an accepted manifest means
the manifest and the seal disagree.

Dropping the exact entry count also made duplicates acceptable: adjacent
duplicates satisfy the sortedness check, set equality collapses them, and the
tree digest is recomputed from the payload's own entries so it stays
self-consistent. An explicit uniqueness check is restored.

And the themes copy loop now refuses a non-file BY NAME instead of skipping it.
A skipped entry makes the isolated root diverge from the tracked tree in silence,
and the seal seals what the child sees without ever comparing back to the source,
so the divergence would surface later as a launcher failure with no named cause.
The tracked directory is flat today, so nothing was being dropped; the refusal is
for the day it is not.

Controls run against the COMMITTED HEAD rather than master, because master's
validator still carries the exact count check and would reject the same payloads
for a different reason. Both new tests fail against the head that has the holes
and pass against this one. tests/scripts: 136 passed, 95 skipped.
# Conflicts:
#	docs/architecture-montana-important.svg
#	docs/current_candidate_metrics.md
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 95e56b0e856a7c7436fc21ccd784796513fcc115. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

The materialiser returns a measured count only when it is given an interpreter to
measure with; on the plain path it returns None, and the seal refuses a
non-positive count. The fixture's declared value is what the acceptance validator
checks, so that is what the seal is asked for.

Windows skips this POSIX-only test, so the mistake was invisible in every local
run and only the Ubuntu job could show it. Measured directly at the pushed head
in a native Linux worktree rather than by waiting for another CI round; that
probe is now a workspace tool.
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 5c2e358ea2cf355af0263e612e7d01c40ab7ee70. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

The seal walks the topology BOTH materialisers produce: the complete one writes
two files and the empty template directory, the isolated one writes the rest. The
round-trip test built only the isolated half, so the seal refused it with a
topology error on Ubuntu while Windows skipped the test entirely and said nothing.

The complete materialiser cannot be called here because it also measures the
reading count in a subprocess and refuses without one, so its two files and its
directory are written the same way, and the assertions afterwards check the union
against what the seal expects. If either materialiser grows a file, this test says
so instead of drifting.

Found by fetching the preserved output from the candidate artifact. The job
summary prints only the failed node ID, which is how the previous round of this
same test was misread.
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 87c7a885c861ae727f00da3c7cd335199637c0a4. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

# Conflicts:
#	docs/architecture-montana-important.svg
#	docs/current_candidate_metrics.md
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 562f0520295ff97c8db001992e96b2c005e36b5c. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

soak measurement added 2 commits August 20, 2026 06:22
# Conflicts:
#	docs/architecture-montana-important.svg
#	docs/current_candidate_metrics.md
#	scripts/soak_mock_stack.py
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is 852304b3b46721af75fe1e85d91a0347f8fdbc63. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

soak measurement added 2 commits August 20, 2026 06:35
…he wrong reason

The reviewer found that three tests passed without exercising anything, and
measurement confirmed it: with the theme presence check and the uniqueness check
both deleted from production, all three still passed.

Two causes, and the first is a merge interaction rather than an error at writing
time. The payload helpers carried the instrument name as a literal, and the
fixture moved to another instrument on master, so the validator rejected every
payload on the instrument before the condition under test was reached. Both
helpers now read the runner constant that the validator's own helper reads, so
the two cannot drift apart again.

The second is the theme presence test itself. It hand built a payload with one
entry and a zeroed tree hash, so the validator rejected it on the hash long
before the theme check. It now uses the same helper the positive cases use, so
the tree hash is real and the file set is complete, and the only thing missing is
a member inside the themes directory. That makes the theme check the condition
that decides.

Each of the three guards was then removed from production one at a time, and
each is now caught by exactly the test that should catch it: the theme presence
check, the uniqueness check, and the rule that the two sealed directories are not
alike. The last one is the original defect this branch exists to remove.
@test1card

Copy link
Copy Markdown
Owner Author

@codex review

Head is ec791eece35ff12bb8bc4f930d9203f9160cd51b. A lane closed the live review findings; the coordinator ran the landing gates on this tree -- byte-order-mark, encoding and parse checks on every changed file, a refusal on any tree that deletes more than it adds, ruff check and ruff format --check on the changed Python, the derived documentation pair regenerated to a fixed point, and the documentation gate green.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: ec791eece3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@test1card
test1card merged commit 75323a2 into master Aug 20, 2026
28 checks passed
@test1card
test1card deleted the fix/soak-isolated-config-theme-packs branch August 20, 2026 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant