Repository navigation
Expand file tree
/
Copy pathdocker-compose.dev.yml
More file actions
222 lines (217 loc) · 10.9 KB
/
Copy pathdocker-compose.dev.yml
File metadata and controls
222 lines (217 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# Development-focused Docker Compose
# Usage: docker-compose -f docker-compose.dev.yml up
version: '3.8'
services:
# Julia API Backend - Core computation engine
julia-api:
# Named so test-runner and cli use this exact image under any project name.
image: deltasignal-julia-api
build:
context: .
dockerfile: Dockerfile
target: julia-builder
ports:
- "8080:8080"
environment:
- JULIA_NUM_THREADS=4
- JULIA_ENV=development
# AND-cluster aggregator mode for benchmark tuning.
# Winning config default is hill_log; override via host env
# (DS_AND_MODE=min|signed|geomean|multiplicative|hill_sat).
- DS_AND_MODE=${DS_AND_MODE:-hill_sat}
# OR-cluster aggregation. "max" = best-available alternative (default);
# "mean" = each alternative carries weight (registers single-member knockouts).
- DS_OR_MODE=${DS_OR_MODE:-mean}
# Inhibitor strength β applied uniformly to every inhibitor edge. Default
# empty = use per-edge β (currently all 0, i.e. no inhibition). Set to a
# single principled value (e.g. 1.0) as the publication-baseline setting.
- DS_INHIBITOR_BETA=${DS_INHIBITOR_BETA:-}
# Selects inhibition formula (spec | krep | divide | devspec | inversion).
# divide is the synthetic-validated default for the publication baseline.
- DS_INHIBITION_MODE=${DS_INHIBITION_MODE:-divide}
# Smoothing constant ε for divide-form inhibition; non-load-bearing in
# [0.0005, 0.01].
- DS_INHIBITOR_EPS=${DS_INHIBITOR_EPS:-1e-12}
# Floor for divide-form H. 0 = full repression possible; 0.95 = each
# inhibitor edge can only repress by 5% (proposed for negative-feedback
# loops that otherwise over-repress through compounding).
- DS_INHIBITOR_FLOOR=${DS_INHIBITOR_FLOOR:-0.0}
# Scope: "loops" (default) applies the floor only to inhibitor edges in
# short negative-feedback loops; "all" applies it to every inhibitor.
- DS_INHIBITOR_FLOOR_SCOPE=${DS_INHIBITOR_FLOOR_SCOPE:-loops}
# Max forward-hops from target back to inhibitor to count as a "short loop".
- DS_LOOP_DEPTH=${DS_LOOP_DEPTH:-3}
# K parameter for the krep formula H = K^m/(K^m+x^m). Unused if divide.
- DS_INHIBITOR_K=${DS_INHIBITOR_K:-0.1}
# hill_sat boundary-transition width (Hjelmfelt smoothing). Identity
# outside ~ε of the UI=0 and UI=100 boundaries; small default keeps the
# operating range (UI 0.25–10) effectively exact-multiplicative.
- DS_HILL_SAT_EPS=${DS_HILL_SAT_EPS:-1e-9}
# hill_sat inhibition de-repression cap (max H value on knockout).
- DS_HILL_SAT_H_MAX=${DS_HILL_SAT_H_MAX:-10.0}
# hill_log saturation point — log of max fold-change (default log(100) ≈ 4.605).
# Lower → sharper saturation. Higher → closer to pure multiplication.
- DS_HILL_LOG_ZMAX=${DS_HILL_LOG_ZMAX:-10.0}
# Depletion-edge de-repression cap. catalyst→substrate edges with
# edge_type="depletion" are ALWAYS divide-form: H = (b+ε)/(x+ε), capped
# here. When the catalyst is knocked out (x → 0), substrate boosted by
# ~H_max (e.g. PTEN-KO → PIP3 up).
- DS_DEPLETION_H_MAX=${DS_DEPLETION_H_MAX:-10.0}
# Symmetric with H_MAX: depletion may suppress at most as hard as it
# de-represses. Was floored at ZERO. See specs/011.
- DS_DEPLETION_H_MIN=${DS_DEPLETION_H_MIN:-0.1}
# Damping for the steady-state penalty solver. 0 = original feed-forward
# iteration (converges in network-depth steps for acyclic, oscillates in
# cyclic). >0 = damped x ← (1-λ)·x + λ·F(x), better convergence for
# feedback loops. Observations stay hard-pinned regardless.
- DS_DAMPING=${DS_DAMPING:-0.0}
# Pass-through recycle suppression. 0 = off (default). When set, an
# `output` edge R→E is dropped whenever the reverse input edge E→R also
# exists — i.e. reaction R both consumes and re-emits the same entity E
# (a stable scaffold/participant threaded through many reactions, e.g.
# active p53). Such a "producer" only recycles E and otherwise pins it at
# baseline via OR-max, masking upstream knockouts. Dropping it as a
# producer lets E track its NET producers; E is still consumed and R's
# other outputs are untouched. See core/reaction_model.jl.
- DS_DROP_PASSTHROUGH=${DS_DROP_PASSTHROUGH:-0}
# Limiting-reactant aggregation for assembly (member→complex) edges. 0 =
# off (default). When set, the AND inputs that come from edge_type
# "assembly" are combined with min() rather than the permissive
# DS_AND_MODE: a complex cannot exceed its scarcest subunit, so
# overexpressing one subunit of a many-membered complex no longer drives
# the whole complex up. Selective (only assembly edges), so catalytic /
# signaling propagation is untouched. See core/reaction_model.jl.
- DS_ASSEMBLY_LIMITING=${DS_ASSEMBLY_LIMITING:-0}
# SCC-aware solving. 0 = off (default, original behaviour). When set,
# the solver computes strongly-connected components and relaxes catalyst
# edges that close a recycling cycle (catalyst source in the same SCC as
# the target) — the catalyst is read at baseline as a conserved-moiety
# modulator, dissolving artifactual recycling SCCs (e.g. TP53 1250→50)
# without editing the network. See bench/analysis/scc_edge_breakdown.py.
- DS_SCC_SOLVE=${DS_SCC_SOLVE:-1}
# Per-SCC damping for the SCC-condensation solver (only used when
# DS_SCC_SOLVE=1). Confined to strongly-connected components; the acyclic
# majority is solved exactly regardless.
- DS_SCC_DAMPING=${DS_SCC_DAMPING:-0.5}
# Optional layer on the SCC solver: relax recycling-catalyst back-edges,
# reading the catalyst at its component-entry (frozen-supply) value.
- DS_SCC_BREAK_CATALYST=${DS_SCC_BREAK_CATALYST:-0}
# Type-aware loop handling: negative-feedback SCCs get a bounded transient
# relaxation instead of full convergence (which buffers/inverts the
# measured transient). "converge" (default) = plain v2.
- DS_SCC_NEG_MODE=${DS_SCC_NEG_MODE:-converge}
- DS_SCC_NEG_FRAC=${DS_SCC_NEG_FRAC:-0.5}
- DS_SCC_NEG_ITERS=${DS_SCC_NEG_ITERS:-1}
# File of gene stable_ids (one per line) marking transcription-reaction
# inputs, so the solver can identify transcriptional autoregulation loops
# (DS_INHIBITOR_FLOOR_SCOPE=transcription). Empty/unset = inert.
- DS_GENE_STIDS_FILE=${DS_GENE_STIDS_FILE:-/app/bench/gene_stids.txt}
volumes:
- ./src:/app/src:ro
- ./cli:/app/cli:ro
- ./test:/app/test:ro
- ./bench:/app/bench:ro
- ./examples:/app/examples:ro
# Same reason as test-runner: without this the image's baked Project.toml
# wins and the service crash-loops on any dependency added since the
# image was built.
- ./Project.toml:/app/Project.toml:ro
# Pre-generated Reactome pathway catalog from the upstream
# logic-network-generator project. Mounted read-only. Override the host
# path with PATHWAY_CATALOG (e.g. in a .env file) for other checkouts.
# The catalog is the latest VERIFIED build from scripts/catalog.sh, which
# records what produced it; /api/health reports which build is served.
# It used to default to logic-network-generator/output, which was last
# built in July and was silently served for two months.
# Long syntax so a MISSING catalog fails loudly. With the short form,
# docker silently creates the missing source as an empty root-owned
# directory, the API reports a healthy service serving nothing, and the
# empty directory then blocks `catalog.sh` from creating `current`.
- type: bind
source: ${PATHWAY_CATALOG:-${HOME}/deltasignal-catalogs/current}
target: /app/pathway_catalog
read_only: true
bind:
create_host_path: false
- julia-cache:/root/.julia
command: julia --project=/app /app/src/api/server.jl --port=8080 --host=0.0.0.0
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# NOTE: the frontend now lives in the WebsiteAngular workspace, not here.
# This repo is the DeltaSignal engine + HTTP API. Point the Angular dev
# server's proxy at http://localhost:8080 (see docs/API.md). julia-api binds
# 0.0.0.0 so it is reachable from the host.
# Test Runner - On-demand testing
test-runner:
# Same image as julia-api: a separately tagged build of the same target
# went stale (12 months), and its Manifest no longer matched the shared
# julia-cache volume, so every suite died at load (code review 2026-10-02).
image: deltasignal-julia-api
build:
context: .
target: julia-builder
environment:
- JULIA_NUM_THREADS=2
volumes:
- ./src:/app/src:ro
# test_cli_observations includes cli/deltasignal.jl; without this it
# tested the copy baked into the image (code review 2026-10-02).
- ./cli:/app/cli:ro
- ./test:/app/test:ro
- ./examples:/app/examples:ro
# Project.toml is NOT baked-in-and-forgotten: without this mount the
# image's copy wins, and adding any dependency to the repo silently
# breaks every suite in the container with "does not have X in its
# dependencies". A new EXTERNAL dependency still needs a rebuild; a
# stdlib one only needs this.
- ./Project.toml:/app/Project.toml:ro
- julia-cache:/root/.julia
profiles:
- test
# Runs the suites that actually assert, read from test/asserting_suites.txt
# so this cannot drift from CI. It used to run test_basic.jl and
# test_steady_state.jl -- which contain ZERO assertions between them --
# then chain a test_full_pipeline.jl that does not exist, and print
# "All tests passed". A green tick here now means something.
command: |
sh -c '
set -u
failed=""
for f in $$(grep -v "^#" /app/test/asserting_suites.txt | grep -v "^$$"); do
echo "--- test/$$f.jl"
julia --project=/app "/app/test/$$f.jl" || failed="$$failed $$f"
done
if [ -n "$$failed" ]; then
echo "FAILED:$$failed"
exit 1
fi
echo "All asserting suites passed."
'
# CLI Runner - Interactive command execution
cli:
image: deltasignal-julia-api # one image for all three; see test-runner
build:
context: .
target: julia-builder
environment:
- JULIA_NUM_THREADS=4
volumes:
- ./src:/app/src:ro
- ./cli:/app/cli:ro
- ./examples:/app/examples:ro
- ./data:/app/data # For input/output files
- julia-cache:/root/.julia
working_dir: /app
profiles:
- cli
stdin_open: true
tty: true
command: julia --project=/app
volumes:
julia-cache:
driver: local