Repository navigation
feat(analysis): exact TSS/CSS/RSS offsets, and no silent substitutions - #61
Merged
Merged
Conversation
…ditions Library size, CSS, TMM/RSS and median-of-ratios size factors, each returning factors centred to geometric mean 1 and the log-offset a count model is fitted with, plus the declared parameters, the uncentred quantities and a SHA-256 of the offset vector for the manifest. The conditions this code is held to are published first in `docs/statistics/method-conditions/scaling-and-offsets.md` (issue #16). Nothing consumes the module yet: `prepare_analysis_table` still sends `TSS` through the proportional branch and aliases `CSS`/`RSS` to `relative`, and `size_factors` still computes library size divided by its own geometric mean. The wiring and its tests follow in the next commit, in which the current behaviour is deleted rather than replaced silently. Also: the CI test step now posts the tail of a failing `test/runtests.jl` as a check annotation. The job log is served from a storage host that is not reachable from every environment that needs to read a failure, so the failure message effectively had no reader. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
arena-ai-coding-agent
Bot
requested a review
from hyperpolymath
as a code owner
September 25, 2026 20:40
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
arena-ai-coding-agent
Bot
force-pushed
the
arena/01a0da3a-metamanifold-webui
branch
from
September 25, 2026 20:40
122eefd to
2280808
Compare
hyperpolymath
approved these changes
Sep 25, 2026
hyperpolymath
added a commit
that referenced
this pull request
Sep 25, 2026
) Two things in one PR, because they have one cause: the layer that claimed to compute TSS/CSS/RSS offsets did not, and the layer that accepted them refused them. ## 1. The refusal — main is red because of this `NormalizationConfig` canonicalises its method to lower case (`"TSS"` → `"tss"`), while `VALID_NORMALIZATION_FOR_METHOD` listed `"TSS"`, `"CSS"`, `"RSS"`. The membership test therefore failed for those three spellings and `AnalysisConfig` raised `normalization.method 'tss' incompatible with method 'nb_glm'` — including for the existing `test/unit/test_execution.jl` testset *TSS offset for NB_GLM*, which constructs `method="TSS"` exactly as the documentation instructs. That is the failure behind the red `Julia tests` job on the TSS-offsets commits; it is not a flaky test and it is not the new estimation layer. The table and both comparisons (constructor, `validate_config`) are lower case now, the JSON-schema enum still accepts the upper-case spellings for existing documents, and `test/unit/test_scaling.jl` asserts that every admissible spelling of every method name is accepted. ## 2. The wiring — issue #16's offsets are computed, not aliased `prepare_analysis_table` now computes scaling factors through `src/analysis/scaling.jl` and hands the offset to the fit: | declared | response | offset | |---|---|---| | `tss` / `none` (count model) | counts | `log(library size)` | | `css` | counts | `log` cumulative sum at the declared `css_quantile` | | `rss` (TMM) | counts | `log` trimmed weighted mean of log-ratios to a reference sample | | `size_factors` | counts | `log` median-of-ratios (RLE) — the estimator the name claimed | | `relative` | proportions | none (a transform, not an offset) | Previously `css`/`rss` were aliased to `relative` under `@warn`, `tss` did that for every method but `nb_glm`, and `size_factors` computed library-size centring wearing DESeq2's name. `css`/`rss` are now refused for a response with no counts to offset — in the configuration layer and again in the execution path. `css_quantile` (0.75), `tmm_ref_column` (chosen the way edgeR chooses it, and recorded), `tmm_log_ratio_trim` (0.3) and `tmm_sum_trim` (0.05) are validated in the constructor, included in the config hash and canonical JSON, round-tripped through `to_json`/`from_json`/Nickel/DEED, mirrored in the JSON schema and Nickel contracts, exposed through the server's configuration route, and explained in `context_help` and the frontend help. A run that declared a different quantile is a different run. `diagnostics.checks["scaling"]` and the manifest provenance record the kind, the definition, the parameters, the raw quantities before centring and a SHA-256 of the offset vector. ## Evidence - `test/unit/test_scaling.jl`: known answers with the arithmetic written beside them; properties a wrong implementation fails (feature permutation, a sample that is an exact multiple of another, invariance to a shared constant); the CSS outlier-robustness property; negative controls for every refusal (zero-total sample, zero CSS cumulative sum, unknown reference, disjoint supports, out-of-range trims); the integration path through `prepare_analysis_table`; and a base-R transcription of the same conditions, which skips **loudly by name** where R is unreachable. - Conditions document, published before the implementation and merged in #61: `docs/statistics/method-conditions/scaling-and-offsets.md`. - Local gates: `check-spdx.sh` OK (284 files), `check-format.sh` OK (331 files), `check-lint.sh` OK (`tsc --noEmit` clean over `frontend/src`). ## Not claimed Parity with `metagenomeSeq::cumNorm` and `edgeR::calcNormFactors` at 1e-6 is **not** verified: neither package is in `renv.lock`, and this PR does not add an unpinned R dependency to make a test pass. The base-R transcription catches implementation slips, not specification errors. That outstanding condition stays recorded in issue #16 and in the conditions document rather than being asserted as met. Closes #16. Co-authored-by: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
hyperpolymath
added a commit
that referenced
this pull request
Sep 25, 2026
…salvageable delta of #71) (#72) <!-- SPDX-License-Identifier: CC-BY-SA-4.0 --> ## Summary Re-anchors **the one genuinely missing piece** of PR #71 onto `main`, and documents why everything else in that PR is already here in newer form. ## Why PR #71 cannot merge (measured, 2026-09-26) 1. **Wrong lineage → `mergeable: CONFLICTING` (DIRTY).** The PR branch is built on the **upstream parent's history** (`JoshuaJewell:main` = `ecefb1c` is an ancestor; the PR = upstream + 3 commits). `main` here shares only the **initial commit** `7884553` with it — the exact fork↔upstream divergence documented in `docs/integration/conflict-map-2026-09-25.md`. A test merge surfaces **38 conflicting files** (add/add: ci.yml, ui.yml, package.json, MetaManifold.jl, Execution.jl, tests, docs, binary `bun.lock`). 2. **Content is ~99% superseded.** Of the PR's 319 changed files, **281 are byte-identical with `main` already** (the migration was re-anchored earlier via `0e61f4f` and siblings). Net of `main`, the PR branch has only **+398 lines**, and after filtering to lines the PR itself authored that `main` truly lacks: - **`src/analysis/Execution.jl` (124 lines): stub/mock code** (“Mock p-value”, “Real implementation would call R…”) — replaced on `main` by the real statistics layer (#57–#66). - **Schema/doc notes “TSS/CSS/RSS deferred alias”** — obsolete: `main` implemented exact TSS/CSS/RSS offsets in #61. - **CI action pins** — older than `main`'s (Dependabot keeps `main` at checkout v7.0.1 / setup-julia v3.0.2 …). - **Escape-key dialog handlers** — superseded by native `<dialog>` with `showModal()` (#32), which supplies Escape/role/focus-trap natively. - **`lint_source.jl` undeclared-deps, Justfile bootstrap/setup-full, coupling test** — all present on `main` in deliberately newer forms. - **The 2 CodeQL alerts (“Workflow does not contain permissions”)** — the author already fixed these on their branch (`6b481a3`, `eab8ea0`), and *that* piece is what `main` was still missing. ## Changes - `.github/workflows/ci.yml`: top-level `permissions: contents: read` plus job-level blocks on `repo-hygiene` and `test` (`cicd-squabbler` already declares its own). Mirrors `ui.yml`, which already has a top-level block, and the fix landed on PR #71's branch. ## Recommendation **Close #71** in favour of this PR (its remaining unique content would regress `main`); carry any future application changes to `JoshuaJewell` per the PR template's Base check. ## Testing - `npx js-yaml .github/workflows/ci.yml` parses; `permissions` present at workflow level and on all jobs. - `scripts/check-spdx.sh` OK (291 files), `scripts/check-format.sh` OK (339 files), `scripts/check-lint.sh` advisory (bun not installed in sandbox). Co-authored-by: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
hyperpolymath
added a commit
that referenced
this pull request
Oct 17, 2026
… work (#178) ## Purpose Make the fork's anticipated upstream state concrete while Joshua's reviews/merges remain pending. This is a **draft baseline proposal**, not evidence that upstream has merged anything. The proposed file tree is exactly JoshuaJewell/main at `52feb605176a4b140f4b40c2b74d2f18adec1f72` plus: - upstream #59 at `3c9d352e1f6c85353c2d78ef1ebf28e5fb64c263` - upstream #60 at `ea974a2328f7f44ad9afeb2f10e5803cd4e31e62` - upstream #61 at `d9ea982dc97c958405e1ff6f57f1b0d8d9b221d1` Resulting tree: `b27daa7f1aa5fa84f320ddae522fa5f2a15ebef5`. ## Effect on fork main This deliberately removes fork-only content from the proposed active baseline: 74 files differ from current main. The existing main commit `491a3e0702ca8ca40e411860d6166523b298b3ac` is the first parent, and all three repair heads are additional parents, preserving the work in history. No existing branch is deleted or rewritten. Do not submit this integration branch upstream. **Before merging:** decide whether main should be the upstream-aligned baseline, with unfinished work isolated onto feature branches. This PR removes real fork features from the active tree, not just stale merge metadata. Recheck upstream and repair heads after Joshua's final decisions; their eventual file tree may change. ## Branch audit There were seven total branches when inspected: main and six additional branches. | Branches | Finding | Disposition | | --- | --- | --- | | repair/permanova-proofs | Clean pending upstream #59 | Keep until merged | | repair/documentation | Clean pending upstream #60 | Keep until merged | | repair/dada2-base-r | Clean pending upstream #61 | Keep until merged | | upstream/permanova-proofs, upstream/docs-community, upstream/dada2-base-r | All three have identical tree 2361ab8; old contaminated submissions, not independent WIP | Retire after baseline decision; no unique feature work needs completing on these branches | | main | Contains additional work beyond the repaired upstream contributions | Preserve and isolate selected changes | Compared with the old three branches, main changes only .gitignore, the differential fixture, the restored deferred-issues specification and removal of the duplicate root code of conduct. Their substantive work is preserved. ## Genuine work to isolate and finish These are code-review findings, not claims that the features have passed a fresh full validation. | Work | Evidence / remaining work | | --- | --- | | glmGamPoi dispersion | Actual implementation and configuration exist, but glmGamPoi is absent from renv.lock. Existing tests do not establish successful reference fits through this path. Pin dependencies and validate against trusted R fits before treating it as complete. | | Significance proof model | The Agda model makes noncomputed numbers unrepresentable, while the Julia documentation explicitly permits retained pairwise rows after an omnibus failure. Reconcile model and implementation; do not claim the proof establishes the Julia representation's behavior. | | Canonical JSON/JCS | Utility and fixtures exist; no production callers found beyond module inclusion/export. Establish conformance and choose an actual integration point before claiming end-to-end provenance. | | Memory occupancy | Measurement, algebra/proof integration, tests and scripts exist. Isolate the work, verify sibling dependency pins and real runtime measurements. This is distinct from biological occupancy modelling in issue #18. | | Wildcard-IP origin handling | Separate behavioral change in server middleware. Review address/port parsing and trust assumptions, then run host/origin, DNS-rebinding and CSRF regressions before submission. | | Plot title markup stripping | Small independent helper and usage change; suitable for a focused bugfix after checking its tests and behavior. | Repository layout changes, frontend major upgrades, community policies, automation and other tooling are separate fork-maintenance decisions, not prerequisites for the three upstream repairs. Do not carry forward the obsolete claim in fork AGENTS.md that locked ggplot2 requires tibble: the retained tibble dependency is used by installation/CI tooling. Open planning issues are not evidence of implemented branch WIP; several overlap or describe functionality already upstream. ## Validation - All six repair commits applied together without conflicts. - git diff --cached --check passes. - Local combined tree and GitHub-created tree match exactly. - Latest individual PR CI runs passed: #59 run 38976014775; #60 run 38998820680; #61 run 38998823755. - Combined baseline CI is separate and must be inspected before merging. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Joshua Jewell <developer@joshuajewell.dev> Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Work in progress. Opened early so CI runs against the scaling module while the wiring
lands; the checklist below is filled in as each part arrives.
What this closes
Issue #16 asked for TSS, CSS and RSS as offsets rather than aliases to
relative,and carried the line "Deferred — DO NOT IMPLEMENT IN MILESTONE 3". That line is a scope
decision; it is lifted explicitly at the top of the new conditions document.
What the code did before:
TSS+nb_glmlog(lib_sizes)(the one honest case)TSS+ anything elseCSS,RSSrelative, with a warning; undernb_glma count model was fitted with fractionssize_factorsWhat replaces it
src/analysis/scaling.jl(conditions published first, indocs/statistics/method-conditions/scaling-and-offsets.md):log(library size).(Paulson et al. 2013),
css_quantiledefault 0.75. Refused, by name, when thecumulative sum is zero:
log(0)is not a small number.cumNormStatFast's data-drivenchoice of the quantile is deliberately not implemented — a parameter chosen from the
data is a decision the run has to record.
(Robinson & Oshlack 2010),
tmm_log_ratio_trim0.3,tmm_sum_trim0.05,tmm_ref_columnoptional, reference otherwise chosen the way edgeR chooses it.All four return factors centred to geometric mean 1, the log-offset, the declared
parameters, the uncentred quantities and a SHA-256 of the offset vector. Refusals are
unsuccessful states: a zero-total sample, an all-zero cumulative sum, a sample with no
positive feature in common with the reference, or no feature positive in every sample all
raise with the reason attached, and none of them is replaced by a factor of 1.
Evidence
test/unit/test_scaling.jl: known answers whose arithmetic is written next to theexpected number, properties a wrong implementation fails (feature-permutation
invariance, a sample that is a multiple of another, the CSS outlier property that TSS
does not have), negative controls for every refusal, and the integration path through
prepare_analysis_tabledown to the offset in the manifest.Stated limit, not hidden: parity with
metagenomeSeq::cumNormandedgeR::calcNormFactorsat 1e-6 is not verified here. Neither package is in the pinnedR environment, and this repository does not add an unpinned R dependency to make a test
pass. That acceptance item is recorded as outstanding rather than claimed.
Closes #16 (with the residual condition recorded in the issue thread).