Skip to content

Record the user's workstation WSL decision (112 GB, 60 processors) in the profile and runtime record - #125

Merged
seathatflowsinourveins merged 2 commits into
mainfrom
claude/workstation-wslconfig-20260923
Sep 23, 2026
Merged

seathatflowsinourveins merged 2 commits into
mainfrom
claude/workstation-wslconfig-20260923

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator

Updates the planned-workstation projection and its runtime record to the user's 2026-09-23 decision, which peer session agent-lab-e7 relayed.

  • Settings: [wsl2] memory=112GB processors=60 swap=16GB networkingMode=mirrored plus [experimental] autoMemoryReclaim=gradual sparseVhd=true.
  • Basis:
    • the workstation's memory goes mostly to the native LLM ecosystem, the foundation and the north star;
    • on the laptop (aggregate only), Windows outside WSL held about 24 GB with 9 GB free, and commit charge was 85.7 of 99.7 GB, so a cap near 128 GB would page Windows;
    • rule: re-measure under full load, and raise toward 116-120 GB only if Windows keeps more than 12 GB free.
  • adoption/hardware-profiles.json (wsl-workstation-128gb-projected):
    • 60 logical processors as seen inside WSL (32 cores / 64 threads physical);
    • memory ceiling 112 GB, with about 111 GB projected in /proc/meminfo;
    • swap 16 GB, plus the two experimental settings;
    • recomputed sizing: concurrency cap 16, embedding/RAG tier headroom, job memory max 27.8 GB and high 18.5 GB.
    • It stays a labelled projection.
  • docs/new-workstation-runtime-profile-20260922.md: the .wslconfig row, the coexistence and free -g figures now reflect 112 GB, and the status reads "decided 2026-09-23, not yet applied".

Checks: hardware-profile tests OK, full unittest OK, validate.py and the evidence sort check pass, and guarded gitleaks found no leaks.

🤖 Generated with Claude Code

…60, swap=16GB, reclaim and sparse VHD

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-23T16:35:23.266915Z b2784d8 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@seathatflowsinourveins
seathatflowsinourveins enabled auto-merge (squash) September 23, 2026 16:30
@seathatflowsinourveins
seathatflowsinourveins merged commit 290bfdd into main Sep 23, 2026
23 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/workstation-wslconfig-20260923 branch September 23, 2026 16:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2784d805c

ℹ️ 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".

Comment on lines +101 to +104
"cores": 60,
"physical_ram_gb": 128,
"wslconfig_memory_gb": 100,
"ram_gb_proc_meminfo_projected": 99,
"gpu_vram_gb": 24
"wslconfig_memory_gb": 112,
"ram_gb_proc_meminfo_projected": 111,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Regenerate the new-host grand-list outputs

On this exact commit, python3 scripts/new_host_grand_list.py --check exits 1 and reports catalogs/landscape/new-host-grand-list.json and docs/new-host-grand-list.md as stale. The JSON still publishes this host as 32 cores with a 100 GB cap and 99 GB projected memory, so the checked-in new-host artifact disagrees with the new 60/112/111 profile and the dedicated CI step in .github/workflows/validate.yml fails; regenerate and commit both outputs and their evidence hashes.

Useful? React with 👍 / 👎.

| `workflowSizeGuideline` | `unrestricted` | 2026-09-21 decision; lean agents cut the fixed child prompt from about 42k to 8–18k tokens | adopted |
| Codex `max_concurrent_threads_per_session` | 3 (excludes the primary thread) | `.codex/config.toml`; Codex config reference fetched 2026-09-22 | no tracked multi-agent Codex job measured at 3 |
| `%UserProfile%\.wslconfig` | `[wsl2] memory=96GB processors=60 swap=16GB networkingMode=mirrored` | proposal: `processors` counts logical processors and the 5975WX has 32 cores / 64 threads, so 60 leaves 4 logical processors (2 cores) and 32 GB to Windows; verify the topology with `Get-CimInstance Win32_Processor \| Select-Object NumberOfCores,NumberOfLogicalProcessors` and WSL `lscpu` before setting it; the laptop's file sets only `networkingMode` | proposal, never applied |
| `%UserProfile%\.wslconfig` | `[wsl2] memory=112GB processors=60 swap=16GB networkingMode=mirrored` plus `[experimental] autoMemoryReclaim=gradual sparseVhd=true` | user decision 2026-09-23, replacing the 96 GB proposal: the workstation's memory goes mostly to the native LLM ecosystem, the foundation and the north star; laptop measurements (Windows outside WSL held about 24 GB with 9 GB free, commit charge 85.7 of 99.7 GB) show a cap near 128 GB would page Windows; re-measure under full load and raise toward 116-120 GB only if Windows keeps more than 12 GB free. Earlier proposal notes: `processors` counts logical processors and the 5975WX has 32 cores / 64 threads, so 60 leaves 4 logical processors (2 cores) and 32 GB to Windows; verify the topology with `Get-CimInstance Win32_Processor \| Select-Object NumberOfCores,NumberOfLogicalProcessors` and WSL `lscpu` before setting it; the laptop's file sets only `networkingMode` | decided 2026-09-23, not yet applied |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recalculate the Windows headroom for the 112 GB cap

With 128 GB of physical RAM, memory=112GB leaves at most 16 GB of physical headroom when WSL reaches its cap, not the 32 GB this updated row still states; 32 GB belonged to the old 96 GB proposal. Because step 0 tells new-host operators to write this configuration and the basis uses Windows free memory to decide whether it is safe to raise the cap, retaining the old figure makes the selected configuration look safer than it is; state the current 16 GB headroom or clearly isolate 32 GB as historical context.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

},
"sizing_arithmetic": {
"workflow_concurrency_cap": "min(16, 32 - 2) = 16",
"workflow_concurrency_cap": "min(16, 60 - 2) = 16 (nproc inside WSL is the .wslconfig processors=60)",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the concurrency result parseable by the grand-list generator

scripts/new_host_grand_list.py:tier_value extracts the text after the last =, so the newly appended processors=60 annotation makes this value reduce to 60) rather than 16. After the stale outputs from the earlier finding are regenerated, the new-host Markdown table will therefore advertise a concurrency cap of 60); keep the annotation from adding another equals sign or otherwise make the stored result unambiguous.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

| `workflowSizeGuideline` | `unrestricted` | 2026-09-21 decision; lean agents cut the fixed child prompt from about 42k to 8–18k tokens | adopted |
| Codex `max_concurrent_threads_per_session` | 3 (excludes the primary thread) | `.codex/config.toml`; Codex config reference fetched 2026-09-22 | no tracked multi-agent Codex job measured at 3 |
| `%UserProfile%\.wslconfig` | `[wsl2] memory=96GB processors=60 swap=16GB networkingMode=mirrored` | proposal: `processors` counts logical processors and the 5975WX has 32 cores / 64 threads, so 60 leaves 4 logical processors (2 cores) and 32 GB to Windows; verify the topology with `Get-CimInstance Win32_Processor \| Select-Object NumberOfCores,NumberOfLogicalProcessors` and WSL `lscpu` before setting it; the laptop's file sets only `networkingMode` | proposal, never applied |
| `%UserProfile%\.wslconfig` | `[wsl2] memory=112GB processors=60 swap=16GB networkingMode=mirrored` plus `[experimental] autoMemoryReclaim=gradual sparseVhd=true` | user decision 2026-09-23, replacing the 96 GB proposal: the workstation's memory goes mostly to the native LLM ecosystem, the foundation and the north star; laptop measurements (Windows outside WSL held about 24 GB with 9 GB free, commit charge 85.7 of 99.7 GB) show a cap near 128 GB would page Windows; re-measure under full load and raise toward 116-120 GB only if Windows keeps more than 12 GB free. Earlier proposal notes: `processors` counts logical processors and the 5975WX has 32 cores / 64 threads, so 60 leaves 4 logical processors (2 cores) and 32 GB to Windows; verify the topology with `Get-CimInstance Win32_Processor \| Select-Object NumberOfCores,NumberOfLogicalProcessors` and WSL `lscpu` before setting it; the laptop's file sets only `networkingMode` | decided 2026-09-23, not yet applied |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the handwritten new-host setup instructions

docs/next-host-stages.md lines 23–26, the repository's machine-setup entry point, still tell operators to apply memory=96GB processors=60 swap=16GB and say the profile's 100 GB assumption needs reconciliation. This commit instead declares 112 GB decided and replaces both earlier proposals, but does not update that handwritten guide, so an operator following it will use the obsolete limit even after the generated grand-list outputs are refreshed.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

seathatflowsinourveins added a commit that referenced this pull request Sep 23, 2026
…ence (#130)

* Stop bootstrap.md's release-commit citation from going stale

adoption/bootstrap.md:16-17 pinned a literal commit (bdd04ca..., the
v2026.09.22.1 tag) next to v2026.09.23's release_tag in prose. Point at
adoption/manifest.json's own source.release_commit instead of a copy that
the next re-pin would leave stale.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Fail loudly on missing measured evidence; add qualified local models

Two related gaps in the new-host evidence loop:

- scripts/new_host_grand_list.py silently gave null measured_tiers when a
  native_proven hosts[] entry named a .json evidence file that did not
  exist. It now fails (exit 1) instead, and carries each host's own
  `measured` block (and nested fields such as `mlx_smoke`) through to the
  generated JSON and a compact Markdown column. A native_proven entry whose
  evidence is prose (a hosted-CI-run citation, not a report path) is not
  held to the file-exists check.

- There was no structured place to record which local model weights were
  qualified on which runtime and host. adoption/host-receipt.schema.json
  gains an optional qualified_models[] array (model_id, revision, runtime,
  runtime_version, bars, result); scripts/host_receipts.py record supports
  --qualified-model (repeatable JSON) and --qualified-models-file, and
  carries the field through build_summary(); scripts/component_matrix.py
  surfaces it per platform on the runtime component's winner row; and
  scripts/new_host_grand_list.py adds a "Qualified local models" section.
  This is informational only: it never marks anything accepted by itself,
  and the platform_status flip rule (scripts/platform_status.py) still
  governs.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Add hardware_profile.py --record-host, the missing hosts[] writer

adoption/hardware-profiles.json hosts[] had no script writer and no
structural check; a measured host could only be added by hand. Add
scripts/hardware_profile.py --record-host <host-id>:

- writes the measured report to
  evidence/artifacts/hw-profiles/<host-id>/profile.json and registers it in
  manifests/evidence.json (the same host_receipts.register_file helper
  record/review use);
- adds or updates the hosts[] entry (evidence_class native_proven,
  evidence pointing at that file), keeping the entry's other fields across
  a re-record;
- enforces the <name>-<yyyymmdd> id convention host_receipts.py already
  uses for measured hosts (a labelled_projection host id still needs to end
  "-projected");
- sanitizes the report (scripts/host_receipts.py's sanitize(), which also
  drives the committed this-host.json's redaction) and refuses to write if
  it still matches PRIVATE_CONTENT afterward.

validate_hosts() is the new hosts[] schema check (required keys, a known
evidence_class, no duplicate id, the id conventions above, and --
when a root is given -- that a measured entry's evidence file actually
exists); it runs in tests/test_hardware_profile.py against both synthetic
fixtures and the real shipped hosts[].

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Add scripts/verdict_flip_candidates.py: report-only flip-candidate finder

Landscape winners[].platform_status only moves through a
record_verdicts.py re-record; nothing previously surfaced when recorded
evidence already supports more than a row declares. The macOS flip rule
(scripts/component_matrix.py's flip-rule check, via
scripts/landscape.ENFORCED_PLATFORMS) only rejects a declaration that
claims *too much*, only for macos-arm64, and only fails CI -- it never
lists what could now claim more, and never covers linux-wsl2-x86_64.

scripts/verdict_flip_candidates.py calls scripts/platform_status.py's
platform_status() -- the one function record_verdicts.py, landscape.py and
component_matrix.py all use -- for every winner and platform in
catalogs/landscape/{foundation,us-equities}.json, and lists rows whose
derived status outranks the declared one, with the qualifying receipts.
Read-only and report-only: it selects nothing, records nothing, and exits 0
whenever the input parses, regardless of what it finds; only malformed
input is an error.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Wire verdict-flip reporting and gap-evidence checks into CI

Three gaps confirmed against the real validate.yml before wiring (per the
dry-run findings): the macOS-only flip rule never reported a flip
candidate; tools/sota-convergence/gap_crosswalk.py build --check and
gap_wave_ledger.py --check existed and were tested but never ran in CI, so
a stale crosswalk or wave ledger could pass silently.

- scripts/verdict_flip_candidates.py runs as a report-only step (piped to
  the job summary); it always exits 0 on well-formed input, so it cannot
  fail the build.
- `gap_crosswalk.py build --check` passes on main as it stands; wired as an
  ordinary blocking check like the other --check steps.
- `gap_wave_ledger.py --check` needs required --wave/--owner flags (the
  task's literal invocation has none); the combination that reproduces the
  checked-in combined ledger
  (gap-wave2-20260923+gap-wave3-20260923--gap-resolution.json) --
  `--wave gap-wave2-20260923 --wave gap-wave3-20260923 --owner
  gap-resolution` -- passes on main and is wired as that exact command.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Document the new-host loop in one place

docs/contributing-evidence.md scattered the new-host steps (bootstrap,
measure, record, refresh derived views, validate, how a flip happens)
across several sections with no single ordered list. Add "0. The new-host
loop, in one place" naming, in order: bootstrap.md; hardware_profile.py
--record-host; host_receipts.py record (--qualified-model for local model
qualifications); component_matrix.py --write then new_host_grand_list.py
--write; verdict_flip_candidates.py; the validate commands plus
`python3 -m unittest` (this repository uses unittest, not pytest, which
is not installed); and that a platform_status flip is a separate step,
done by record_verdicts.py's owner through its own lane process.

docs/next-host-stages.md gets a pointer to that section, and its two
per-host step lists are updated to name --record-host and --qualified-model
instead of the older by-hand "add the measured entry" instruction.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Regenerate derived outputs for the qualified-models and hosts[] changes

python3 scripts/component_matrix.py --write, then
python3 scripts/new_host_grand_list.py --write, then
python3 scripts/evidence_manifest.py --write, plus re-registering every
source file this branch touched that manifests/evidence.json already
tracked a hash for (host_receipts.register_file, the same helper --write
uses for its own outputs). flip_rule_violations stayed 0 throughout.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Record the workstation WSL memory decision (112 GB) with the measured Windows-side evidence

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Scope --record-host sanitization to only the new entry; validate before writing

Two review findings (human + Codex, both against 48471ea) on
scripts/hardware_profile.py's cmd_record_host:

- It ran host_receipts.sanitize() over the whole serialized
  hardware-profiles.json document. sanitize() replaces every occurrence of
  $USER in the text it is given, and $USER is often a short, common word
  ("mac", "runner", "ram", "max", ...) that legitimately appears inside
  unrelated pre-existing content: an id like
  "github-macos-15-arm64-runner", or -- more seriously -- a config key like
  "max_fraction_of_ram" in the same document's own
  layers.ecosystem_bounded_run, which a whole-document sanitize renamed,
  making the *next* recommend() call raise KeyError. Now only the new/
  updated hosts[] entry's own serialized text is sanitized (and the fresh
  measured report, which has no such shared keys to corrupt); the whole
  document is only regex-scanned (never mutated) for a final defensive
  check.
- The evidence file was written and registered before validate_hosts() ran.
  Validation (over the whole hosts[] array, so a pre-existing malformed
  entry elsewhere also blocks the write) now runs first, with root=None
  (skipping the evidence-file-exists check, which cannot pass before that
  file is written) -- so a failure leaves no evidence file, no manifest
  registration and no changed hardware-profiles.json behind.

Tests cover USER in {runner, mac, ram, max} leaving every existing hosts[]
entry and the whole layers config byte-identical, a subsequent recommend()
call not raising, and a pre-existing bad entry blocking the write with
nothing written.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Read measured values from a --record-host host's evidence file too

Codex review (against 48471ea): scripts/new_host_grand_list.py's
build_hosts() only took a host's `measured` block from the hosts[] entry
itself. scripts/hardware_profile.py --record-host never puts `measured` on
the entry (only `evidence`, a path to the report that holds it), so a
freshly recorded host's real measurements never reached the grand list --
`measured` stayed null even though the evidence file had them. Read
`measured` from the evidence file too when the entry has none of its own
(an entry's own inline `measured`, as the shipped
github-macos-15-arm64-runner entry has it, still wins). Tests cover the
fallback, the entry-wins-when-both-present case, and a full
record-then-build-hosts round trip.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Validate each --qualified-model entry against schema before running commands

Codex review (against 48471ea): the CLI's own pre-execution check for
--qualified-model only looked at required keys and whether result was in
{pass, fail} via `not in` against a set, which raises an uncaught TypeError
for an unhashable value such as `result: []`. It also never checked
anything else the schema constrains (for example `bars`'s maxLength 400),
so an over-length bars value passed this check, ran the qualification
command(s), and was rejected only afterward by the pre-write
validate_receipt_shape() call -- after the side effect. Replace the
hand-rolled subset check with the same schema-driven validate_against_schema()
this module already uses everywhere else, run over the qualified_models[]
item subschema before any command executes; its equality-based enum check
never raises on a non-hashable value. Tests cover both failure modes,
asserting exit 2 (no traceback) and that no command ran.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Enable pipefail for the verdict-flip step; name the gap checks honestly

Two P2/P3 findings against the CI wiring added earlier this branch:

- The verdict_flip_candidates.py | tee step had no `shell: bash`, so
  without pipefail a malformed-input exit 1 from the reporter would be
  swallowed by tee's own exit 0. Add `shell: bash`, matching the
  release_due step's existing pattern.
- "Check the gap crosswalk is current" and "...wave ledger is current"
  overstated what these --check steps prove: gap_crosswalk.py's build
  reads catalogs/landscape/*.json at a fixed historical commit
  (CURRENT_REV, 92bb279), and the wave ledger reads the checked-in
  crosswalk file, not the current catalogs. Both steps only prove the
  checked-in file still reproduces from its own fixed inputs; neither can
  detect that a layer re-recorded since CURRENT_REV made the crosswalk
  stale. Renamed to say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Document that the gap-crosswalk CI checks are fixed-revision, not live

P3 finding: the reproducibility of gap_crosswalk.py build --check and
gap_wave_ledger.py --check from their own fixed inputs (CURRENT_REV
92bb279 and the checked-in crosswalk, respectively) is not the same as
detecting that either has gone stale against the *current*
catalogs/landscape/*.json open_gaps. Section 4 now says so explicitly, so
a reader does not read the CI wiring as more than it is.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Reword: --record-host adds a dated entry, it doesn't replace the projection

P3 finding: "until python3 scripts/hardware_profile.py runs on each host
and replaces them" implied the labelled-projection hosts[] entry
disappears once a host is measured. --record-host adds a separate, dated
native_proven entry alongside it; the projection entry is neither removed
nor overwritten. Reworded to say to prefer the measured entry once one
exists, not to expect the projection to vanish.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Stop upgrade-evidence.json claiming a reconciliation this record doesn't make

P3 finding: 48471ea's decision block set memory=112GB but the evidence
string still said "the two records need reconciling by their owner; this
manifest does not choose the value" -- stale now that a decision exists.
Reworded to state the decision and point at the hardware-profiles.json
owner's own record of it (catalog PR #125) without this manifest claiming
to have updated that entry itself.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Regenerate derived outputs for the review-round fixes

python3 scripts/component_matrix.py --write, then
python3 scripts/new_host_grand_list.py --write, then
python3 scripts/evidence_manifest.py --write, plus re-registering
evidence/artifacts/host-upgrade-20260923/upgrade-evidence.json (the only
source file this round's fixes touched that manifests/evidence.json
already tracked a hash for). component-evidence-matrix.json was already
byte-identical (no new receipts this round). flip_rule_violations stayed 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Fix tier_value() on a trailing parenthetical note containing '='

Discovered while regenerating after rebasing onto catalog PR #125:
adoption/hardware-profiles.json's wsl-workstation-128gb-projected
workflow_concurrency_cap is now "min(16, 60 - 2) = 16 (nproc inside WSL is
the .wslconfig processors=60)". tier_value()'s rsplit("=", 1) took the
*last* '=' unconditionally, which lands inside that trailing explanatory
note ("processors=60)"), rendering the grand list's concurrency-cap column
as "60)" instead of "16". Strip one trailing, balanced parenthetical note
first (matching parens from the end, so it only touches a string that
actually ends in ")"); a string with several '=' but no trailing note
(the existing ecosystem_job_memory_max_gb style) still takes the result
after the last '=', unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Sanitize only decoded string values, never JSON keys, in --record-host

Round-2 review follow-up (P2): the previous fix still ran
host_receipts.sanitize() over the whole serialized report and entry text.
sanitize() replaces every occurrence of $USER in the text it is given,
which still corrupted the *keys* of the new report/entry themselves: with
USER=ram, "effective_ram_gb" and "ram_gb_proc_meminfo" became
"effective_<user>_gb"/"<user>_gb_proc_meminfo"; with USER=gpu or
USER=cores, the bare "gpu"/"cores" keys became "<user>"; a preserved field
kept from a re-recorded entry (for example "ecosystem_job_memory_max_gb")
was equally at risk under USER=max. The grand list then silently dropped
RAM, GPU or cores for that host.

Add sanitize_values(), which walks the decoded report/entry the way
host_receipts.iter_receipt_strings() walks a receipt for its read-only
privacy scan, but only sanitizes each dict *value*/list *item* that is a
string -- never a dict *key* -- so JSON structure survives regardless of
$USER. Use it for both the report and the entry (including whatever an
existing entry's preserved fields are) in place of the prior
serialize-then-sanitize-the-whole-text approach.

Tests cover USER in {ram, max, gpu, cores, runner, mac}: the written
profile.json's and entry's own keys stay unchanged, and a key preserved
from a prior entry across a re-record survives too.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Fix tier_value() dropping a result glued directly to '('

Round-2 review follow-up (P3): text ending in "(...)" with no separate
trailing note -- e.g. "cap = min(16, 30)" -- was treated the same as a
genuine explanatory note and stripped, returning "min" instead of
"min(16, 30)". Only drop a trailing "(...)" when it is set off by a space
(a real note, like "16 (nproc inside WSL is ...)"); one glued directly
onto a preceding token with no space (a function call, part of the result
expression itself) now stays. The two compose correctly: a genuine
trailing note after a parenthesized result is still dropped, leaving the
parenthesized result intact.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Refuse a --record-host id that contains the local user name, with a clear reason

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Refresh the evidence manifest after rebasing onto main

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

---------

Co-authored-by: seathatflowsinourveins <[email protected]>
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
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