text:
Cops and Robbers: Redacted Primality (Robbers' Thread)
This is the robbers' thread. The cops' thread is here.
Your challenge is to take an uncracked submission from the cops' thread and try to find the original unredacted program. Please comment on the cop's submission when you've cracked their code.

brainfuck, Jo King
>>>>>+>,[>++++++[-<-------->]<+>,]<[-[█<█<]++++++++++<]>[-]>>██[>█>>█>]+[<]<<[<]>█<<+>>[>]█>[>]█+[<]<<[<]>-█>]>>[->]<[-[[<]<]++++++++++<]>[-]>[<█]>]>[>]<[[█]<]<<<<<[<]<<██>>[>]<█[->+<]<█>>[>]<[-[[<]<]++++++++++<]>███>[<<]>[[[>]>████[<]<[-[[<]<]++++++++++<]>[-]>[█<]>]>[>]<[[-]>+[>]<-<[<]<]+<<<<<[<]>[[>]+[[>]>]>[>]>[-<+>]<[<]<[>+[<]>>-<<<<<[[<]<]>>███████>[[█]>]<]<[[<]<]<[█]>]>>>[[>]<->>]]>[[>]>]<<[[[█]<]<]<<<[█]<<█>>>[>]█[-[[<]<]++++++++++<]>>[[>]+[------->++<]>.+.+++++.[---->+<]>+++.>>]>[>]+[------->++<]>++.++.---------.++++.--------.
>>>>>+>,[>++++++[-<-------->]<+>,]<[-[[<]<]++++++++++<]>[-]>>[[[>]>>[>]+[<]<<[<]>[<<+>>[>]>>[>]<+[<]<<[<]>-]>]>>[->]<[-[[<]<]++++++++++<]>[-]>[<<]>]>[>]<[[-]<]<<<<<[<]<<[>>>[>]<[[->+<]<]>>[>]<[-[[<]<]++++++++++<]>[-]>[<<]>[[[>]>[>]+[<]<[-[[<]<]++++++++++<]>[-]>[<<]>]>[>]<[[-]>+[>]<-<[<]<]+<<<<<[<]>[[>]+[[>]>]>[>]>[-<+>]<[<]<[>+[<]>>-<<<<<[[<]<]>>[[-]+>]>[[>]>]<]<[[<]<]<[<]>]>>>[[>]<->>]]>[[>]>]<<[[[-]<]<]<<<[<]<<]>>>[>]<[-[[<]<]++++++++++<]>>[[>]+[------->++<]>.+.+++++.[---->+<]>+++.>>]>[>]+[------->++<]>++.++.---------.++++.--------.

Try it online!
This implements the sieve of Eratosthenes.
The initial >>>>>+>,[>++++++[-<-------->]<+>,] inputs each digit as an character code and subtracts 47 to put it in the range 1-10.  This allows a cell value of 0 to denote spacing between numbers.  The +> near the beginning of this section forces the number to be at least two digits, which will be important soon.
Next, and one of the first things I figured out, is the section <[-[[<]<]++++++++++<]>[-]>.  This appears several times in the code, each with different patterns of redaction, but it was not hard to guess that all of those instances were probably the same code.  This code requires three zeros to the left of the decimal number on the tape, and its effect is to decrement the number.  The last iteration of the loop will put the value 10 two cells left of the number, but the [-] cleans it up.
If the decimal number was 0, there is no extraneous 10 created, and the cell zeroed by [-] is the most significant digit.  The tape head is then at the second-most significant digit (which is why at least two digits are necessary).  Most instances of this snippet are immediately followed by [<<]>, which places the head on a nonzero cell in normal conditions and a zero cell if the original decimal number was zero.  It seems that in this program, the decimal representation of n-1 is used to denote n, so that decrementing to 0 is caught instead of decrementing to -1.
The next part puts the numbers from n-1 (n) down to 0 (1) on the tape:
>[                      until the number reaches zero:
  [                     for each digit:
    [>]>>[>]+[<]<<[<]>  create a placeholder for the next copy
    [                   while the original value of the digit is nonzero:
      <<+               add 1 to copy two cells left (to keep one copy)
      >>[>]>>[>]<+      go to new copy and increment that cell
      [<]<<[<]>-        go back to original digit and decrement
    ]                   (this is effectively the same as [<+>>+<-] but with the cells at variable locations)
  >]                    next digit
  >>[->]                cancel the placeholder 1s that were used for the new copy
  <[-[[<]<]++++++++++<]>[-]>[<<]> decrement
]
>[>]<[[-]<]      clean up the trash 10s on the tape while ending at a known location relative to the last number

Now, these numbers are all on the tape with two zero cells separating them.  <<<<<[<]<< puts us at the final cell of the penultimate number on the tape, which is where we will be in every iteration of the loop.  The loop terminates when all numbers except the original have been handled.
At the start of the loop, we move the current number (last one still on the tape) one cell right to have room to decrement, and then go ahead and decrement:
[>>>[>]<[[->+<]<]>>[>]<[-[[<]<]++++++++++<]>[-]>[<<]>

If this decrement didn't underflow, we proceed to convert the number to unary:
[[[>]>[>]+[<]<[-[[<]<]++++++++++<]>[-]>[<<]>]

Note that this snipped has an unclosed [.  As a result, the rest of this loop is skipped if the number was 0 (representing 1).  After converting to unary, we clear out the leftover 10s, dragging the unary representation with us to the left:
>[>]<[[-]>+[>]<-<[<]<]+

I didn't notice until just now writing this, but the + at the end of this snippet is separated from the unary representation by a single 0.  It is also a part of the unary representation: the sequence 1011...11 will represent 0 mod k.  The following <<<<<[<]> puts us at the beginning of the number k+1, starting a new loop.
The inner loop here "marks" every number on the tape with a 1 on the cell immediately right, and uses the unary representation as a clock to determine which numbers are multiples of k.
[
  [>]+             mark the current decimal number
  [[>]>]           move to end of decimal part of tape
  >[>]             move to 0 in middle of unary "clock"
  >[-<+>]          move the following 1 to the left if possible
  <[<]<            if a 1 was moved this will bring us back to a zero before the start of this "clock";
                   otherwise the looped move command doesn't move us at all and we are at the final 1
  [                if there was no gap (happens every kth iteration):
    >+[<]>>-       reset to original position
    <<<<<[[<]<]>>  go to number that was just marked
    [[-]+>]        replace digits with 0s (cell value 1)
    >[[>]>]<       go back to where we would be without this conditional
  ]
  <[[<]<]<[<]>     return to first unmarked number
]

The [[-]+>] in that section was the last part I figured out.  Before that, I assumed the program was just doing trial divisions, but I couldn't see where the result was used.
This loop ends two cells left of the far left number, and >>>[[>]<->>]] removes the markers placed on the tape and gets us to the end of the tape again.  After that >[[>]>]<<[[[-]<]<] removes either the unary clock or, if this entire segment was skipped, the leftover 10s.  The loop is set to its starting condition with <<<[<]<<].
After this is just reading whether the input number was replaced by 1 at any point:
>>>[>]<[-[[<]<]++++++++++<]>>                      do the check
[[>]+[------->++<]>.+.+++++.[---->+<]>+++.>>]      conditionally print "not "
>[>]+[------->++<]>++.++.---------.++++.--------.  unconditionally print "prime"

Fortunately, the actual output was not redacted at all.

"The night is long that never finds the day." Is it still tonight? :P

@StewieGriffin I was unable to do it that night, and then it just slipped my mind.  Thanks for the reminder.

I don't think I could have explained my own code as well as you did here. Very nice work.

Wolfram Language (Mathematica)
Cracks this answer.

f[x_]:=(p=ToString@Boole@PrimeQ@x;StringMatchQ[p&@@Infinity,RegularExpression@"(\
\n{}\b+, )?1"])

Try it online!

No scrolling necessary to read the code :)

Nice! Quite different from the intended solution, so I won't reveal that yet.

@Pavel What about this? Or still "fundamentally the same"?

Here's a hint: that large blob contains neither Boole not PrimeQ.

Brain-Flak, MegaTom
(({████){██[████)█>(({}))<>}<>{}███{}((██({}))█████{}]██)({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{})██[██()██(()█[()]██{}██}{}<>{})
(({})<>){([[]]{})<>(({}))<>}<>{}{}{{}(([]({}))[({}[{}])])({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{})}([][()])((){[()](<{}>)}{}<>{})

Try it online!
This program performs trial divisions from n-2 down to 1, then outputs 1 if and only if this terminated with the factor 1.

8086 DOS COM by Joshua
xxd representation, because of encodings and null bytes and other scary stuffs:
00000000: 31c0 b90a 0031 dbbe 8100 ac3c 0d74 3c3c  1....1.....<.t<<
00000010: 2075 f7ac 3c0d 7410 2c30 7c2f 3c09 7f2b   u..<.t.,0|/<..+
00000020: 93f7 e193 01c3 ebeb 83fb 027c 19c6 0653  ...........|...S
00000030: 0159 b902 0039 d974 1289 d831 d2f7 f109  .Y...9.t...1....
00000040: d274 0341 ebef c606 5301 4eb4 09ba 5301  .t.A....S.N...S.
00000050: cd21 c341 0d0a 24                        .!.A..$

First disassembled the cop manually, then assembled using yasm. Some bytes have been corrupted by the conerter Joshua used, but I've just treated them like redacted bytes. I'm 99.72% certain about their actual content. It shouldn't take long to fix it if I'm wrong, though. Enjoy:
; A COM file is just a 16-bit flat binary
; loaded at 0x100 in some segment by DOS

org 0x100
bits 16

; Unsurprisingly, we start by converting
; the commandline string to a number. During
; the conversion, SI is a pointer to the
; string, CX is the base, and BX holds the
; partial result
parse_input:
; We'll read the input character by character
; into AL, but we need the resulting digit as
; a 16-bit number. Therefore, initialise AX to
; zero.
    xor ax, ax
    mov cx, 10
    xor bx, bx
; When a DOS program is loaded, it's preceded
; in memory by the Program Segment Prefix,
; which holds the commandline arguments at
; offset 0x81, terminated by a carriage return
    mov si, 0x81

.skip_prog_name:
; Load a character and move the pointer
    lodsb
; If we find the terminator here, the program
; was not given any arguments.
    cmp al, 13
    je finish

    cmp al, ' '
    jne .skip_prog_name

.input_loop:
    lodsb
    cmp al, 13
    je got_input

; If the ASCII value of the character is less
; than the one of '0', error out. Adjust the
; value in AL so that it holds the digit
; itself. This exploits the fact that the
; comparison instruction is just a subtraction
; that throws away the actual result.
    sub al, '0'
    jl finish

; If we have a value larger than 9, this
; character wasn't a digit.
    cmp al, 9
    jg finish

; Multiply the intermediate result by 10 and
; add the new digit to it.

    xchg ax, bx
    mul cx
    xchg ax, bx
    add bx, ax
    jmp .input_loop

got_input:
; The loop below would go haywire when given a
; zero or a one, so make them a special case.
    cmp bx, 2
    jl composite

; Patch the output string to say that it's
; prime
    mov byte[outstr], 'Y'

; BX = number being checked
; CX = loop counter, potential divisor of BX
    mov cx, 2

.loop:
; If CX = BX, we looked everywhere and couldn't
; find a divisor, therefore the number is prime
    cmp cx, bx
    je finish

; DIV takes DX:AX as a 32-bit number for the
; dividend. We don't want nor need the extra
; precision, so we set DX to 0.
    mov ax, bx
    xor dx, dx
    div cx

; DX now contains the remainder. To check if
; it's 0, we perform some noop operation, that
; happens to set the flags appropriately. AND
; and OR are commonly used for this purpose.
; Because of what's presumably a bug in the
; encoder used by Joshua, I do not yet know
; which for certain. However, I can make an
; educated guess. All other instances of the
; bug happened with a codepoint below 32.
; Moreover, no other bytes from that range
; occur in the code. Because an AND would be
; encoded as an exclamation mark, while OR -
; - as a tab, I am highly confident that Joshua
; used an OR.
    or dx, dx
    jz composite

; Increment the counter and loop again!
    inc cx
    jmp .loop

composite:
    mov byte[outstr], 'N'

finish:
    mov ah, 9
    mov dx, outstr
    int 0x21
    ret

outstr:
    db 'A', 13, 10, '$'

The only difference between mine was bx < 2 goes to finish rather than composite. FYI the corruption was due to originally using X as the mask character and not fixing everything up properly when switching to █.

@Joshua I used finish there at first too, but then I remembered that handling 1 correctly is required. About the corruption - that's one of the scenarios I imagined

Jelly
Cracks this answer.
25██26█966836897364918299█0█1█65849159233270█02█837903312854349029387313█ị██v

250126,9668368973649182994001,658491592332700020837903312854349029387313ṖịØJv

Try it online!

Explanation:
Looking at ị and v, I think of building a list of numbers, ịndex it into some list and evaluate it.
The "trivial" way of checking primality in Jelly is ÆP, so (if it can cracks the submission):

The list to be indexed to must contains Æ and P.
The list of indices must be congruent modulo 256 with [14, 81].

So... the list at the start of the program congruent to [14, 81, 49] mod 256 (TIO) and Ṗ pops the last element.

sh + coreutils
Cracks this answer.
e█ec█s█ █c "██████WyAkKHNoIC1jICJg█WNobyBabUZqZEc5eWZIUnlJQ2█2SnlBblhHNG5m██JoYVd3Z0t6SjhkMk1nTFhjSyB8YmFzZTY0IC1kYCIpIC1lcSAxIF0K█b█se6███d`"

exec sh -c "`echo WyAkKHNoIC1jICJgZWNobyBabUZqZEc5eWZIUnlJQ2M2SnlBblhHNG5mSFJoYVd3Z0t6SjhkMk1nTFhjSyB8YmFzZTY0IC1kYCIpIC1lcSAxIF0K|base64 -d`"

No Try it online! this time because of some issues. However you can use jdoodle.
Returns by exit code. 0 (success) for prime, 1 (error) for composite.
The actual command executed is
factor|tr ':' '\n'|tail +2|wc -w

How to crack

Look at the code, recognize Base64.
Learn how to use base64 command.
Know that + is a valid base64 character.
Try to decode.
Apply the wrapper sh -c "`echo ...|base64 -d`" back to the original program.
Generate nested base64 from commands.

Correct method. "Some issues" turns out to be not all machines know about tail +n. When I tried your crack on the machine at work it complained about it. You did unmask the correct code so ... :(

Octave, 86 bytes, Stewie Griffin.
@(x)eval([(str2num(cell2mat([cellstr(reshape('0█1███1█0█0█00',████))])')█'█')','(x)'])
@(x)eval([(str2num(cell2mat([cellstr(reshape('04141113040800',2,[]))])')+'e')','(x)'])

Try it online!
This was a fun one! I struggled with this for a good couple of days.
The first clue was recognizing eval([...,'(x)']) as a construction creating a call to the isprime function, as concatenation of ints and char will implicitly convert the array to char, so the ... needed to be either isprime or an array that had the ASCII values of isprime, [105, 115, 112, 114, 105, 109, 101].
The rest of it was just slogging through documentation to figure out that reshape can take one unknown dimension with [], although I suppose I could have done reshape(...,2, 7) at the same byte count.
Using +'e' (101) instead of +'d' (100) was a nice touch that threw me for another few minutes until I noticed the last digits (unobfuscated) were 00 rather than 01, and with that it was easy.

JavaScript
x=>{if(x<4)return(!0);for(y=x>>>Math.log10(p=████;--y-1;(p=x/y%1)████if(██&&(███))break████return(███)}
x=>{if(x<4)return(!0);for(y=x>>>Math.log10(p=2-1);--y-1;(p=x/y%1)){;;if(!p&&(1<2))break;;;}return(!!p)}

Try it online!
I somehow doubt this is exactly what you had in mind, but it works.

Java (OpenJDK 8), Magic Octopus Urn
class X{public static void main(String[]args){System.out.println(new String(████████[Integer.parseInt(args[0])]).matches("█████████████")?███);}}
class X{public static void main(String[]args){System.out.println(new String(new char[Integer.parseInt(args[0])]).matches(".?|(..+?)\\1+")?0:1);}}

Try it online!
The code is taken from RosettaCode and explained on SO.

Had no idea that it was that popular hah! Had this in my back pocket for a long time. I honestly stole it from a utility file I've had since like... Jeez... 2014?

><>, Esolanging fruit
:1@v>~~:?1n;█$-1<█?=2:}*{█@:$@:

to
:1@v>~~:?1n;
$-1</?=2:}*{%@:$@:

Try it online!
Clever use of redacting a newline confused me for a bit. Doesn't seem to work for 1 or 2 though.

Nice. Any of ^, v, /, or \  for the second blank could have worked there. I now wish I had covered the * instead of the /.

Python 3, 44 bytes, osuka_
p=lambda x,i=2:i>=x or(x%i and p(x,i+1))or 0

Try it online!
Does not work when x<2. The or 0 can be replaced with >0{2 spaces} or even 4 spaces
For the x<2 problem, since i>=x must be put at the front (otherwise there will be an infinite loop), and the i>=x returns true immediately when x<2, so I think that's no fix with that.

So as it turns out, my code doesn't work with x<2 either. Oops. (I probably just tested it with range(2, ...), because i'm stupid)

M, dylnan
ÆPø“;;“»VOḣ2S⁵++3Ọ;”Pv

This probably wasn't the intended solution.
Try it online!
How it works
ÆP is the built-in primality test.
ø beings a new, niladic chain. Since the previous return value (the result of ÆP) goes out of scope, this prints it implicitly.
“;;“» evaluates to the list of strings ["< Aalst" ""], and V tries to eval them. s tries to split its argument into chunks of length 0, which causes the M interpreter to crash, suppressing further output.

Not intended solution but nice. Will update post to cracked soon. If I said the word “zoo” would that lead you to another possible solution?

Hm, that sounds like complex infinity.

Pyth, Mr. Xcoder
q]tQ #aQ{*MyP

Python 3, user71546
import random
def f(z):
 if z<4:return z>>1
 d,s,n,e,c=~-z,0,z,0,50
 while not d&1:d//=2;s+=1
 while n>0:n//=2;e+=1
 random.seed()
 while c>0:
  a=0
  while a<2or a>z-1:
   a,b=0,e
   while b>0:a=a*2+random.randint(0,1);b-=1
  x,r=pow(a,d,z),~-s
  if ~-x and x!=~-z:
   while r>0:
    x,r=pow(x,2,z),~-r
    if not ~-x:return 0
    elif x==~-z:break
   else:return 0
  c-=1
 else:return 1

Try it online!


text:
Make Zero From First 'n' Numbers
Challenge
The challenge is to write a code that takes a positive integer 'n' as an input and displays all the possible ways in which the numbers from 1 - n can be written, with either positive or negative sign in between, such that their sum is equal to zero. Please remember that you may only use addition or subtraction.
For example, if the input is 3, then there are 2 ways to make the sum 0:
 1+2-3=0
-1-2+3=0

Note that, the numbers are in order, starting from 1 till n (which is 3 in this case). As it is evident from the example, the sign of the first number can also be negative, so be careful.
Now, 3 was pretty much simple. Let us list all the ways when we consider the number 7.
 1+2-3+4-5-6+7=0
 1+2-3-4+5+6-7=0
 1-2+3+4-5+6-7=0
 1-2-3-4-5+6+7=0
-1+2+3+4+5-6-7=0
-1+2-3-4+5-6+7=0
-1-2+3+4-5-6+7=0
-1-2+3-4+5+6-7=0

So here, we have got a total of 8 possible ways.

Input And Output
As stated before, the input would be a positive integer. Your output should contain all the possible ways in which the numbers give a sum of zero. In case there is no possible way to do the same, you can output anything you like.
Also, you can print the output in any format you like. But, it should be understandable. For example, you may print it as in the above example. Or, you may just print the signs of the numbers in order. Otherwise, you can also print '0's and '1's in order, where '0' would display negative sign and '1' would display positive sign (or vice versa).
For example, you can represent 1+2-3=0 using:
1+2-3=0
1+2-3
[1,2,-3]
++-
110
001

However, I would recommend using any of the first three formats for simplicity.
You can assume all the inputs to be valid.

Examples
7 ->

 1+2-3+4-5-6+7=0
 1+2-3-4+5+6-7=0
 1-2+3+4-5+6-7=0
 1-2-3-4-5+6+7=0
-1+2+3+4+5-6-7=0
-1+2-3-4+5-6+7=0
-1-2+3+4-5-6+7=0
-1-2+3-4+5+6-7=0

4 ->

 1-2-3+4=0
-1+2+3-4=0

2 -> -

8 ->

 1+2+3+4-5-6-7+8=0
 1+2+3-4+5-6+7-8=0
 1+2-3+4+5+6-7-8=0
 1+2-3-4-5-6+7+8=0
 1-2+3-4-5+6-7+8=0
 1-2-3+4+5-6-7+8=0
 1-2-3+4-5+6+7-8=0
-1+2+3-4+5-6-7+8=0
-1+2+3-4-5+6+7-8=0
-1+2-3+4+5-6+7-8=0
-1-2+3+4+5+6-7-8=0
-1-2+3-4-5-6+7+8=0
-1-2-3+4-5+6-7+8=0
-1-2-3-4+5+6+7-8=0

Scoring
This is code-golf, so the shortest code wins!

Please note that this is not a dupe of https://codegolf.stackexchange.com/questions/8655/golf-the-subset-sum-problem , because this challenge is meant to take only n as input and use all the numbers 1-n in order.

May we represent + as N and - as -N, or is that taking it too far? (e.g. 3 -> [[-3,-3,3], [3,3,-3]])

@JonathanAllan Isn't that mentioned in the list of output formats? Or did I wrongly interpret your question?

I mean like the 0 and 1 option but using N and -N (see my edit above)

@JonathanAllan Yes thats certainly allowed. Make sure you mention that in the answer.

https://oeis.org/search?q=2%2C2%2C0%2C0%2C8%2C14&language=english&go=Search

Haskell, 42 bytes
f n=[l|l<-mapM(\i->[i,-i])[1..n],0==sum l]

Try it online!

42.

Shouldn't it be 0== ?

Jelly, 9 bytes
1,-ṗ×RSÐḟ

Try it online!
Exp
1,-ṗ×RSÐḟ  Main link. Input = n. Assume n=2.
1,-        Literal list [1, -1].
   ṗ       Cartesian power n. Get [[1, 1], [1, -1], [-1, 1], [-1, -1]]
    ×R     Multiply (each list) by Range 1..n.
       Ðḟ  ḟilter out lists with truthy (nonzero)
      S      Sum.

Jelly, 9 bytes
Jonathan Allan's suggestion, output a list of signs.
1,-ṗæ.ÐḟR

Try it online!

How about (ab?)using the lax output format with ,Nṗæ.ÐḟR?

Or alternatively, this output the outputs multiplied by n.

The N and -N output I suggested has been allowed, so that saves one byte :) (just need to mention the format in the answer)

Not sure how recently it was added, but there's a builtin Ø+ to save a byte over 1,-.

Python 2, 62 bytes
f=lambda n,*l:f(n-1,n,*l)+f(n-1,-n,*l)if n else[l]*(sum(l)==0)

Try it online!
Mr. Xcoder saved 4 bytes with a nifty use of starred arguments.

62 bytes using *l instead of l=[]

Perl, 37 36 bytes
perl -E 'map eval||say,glob join"{+,-}",0..<>' <<< 7

Nicely done. You can drop -n and <<< if you replace $_ with pop. It doesn't actually improve your score, but it makes the overall expression shorter ;)

05AB1E, 11 bytes
®X‚¹ãʒ¹L*O_

Try it online!
The output format for e.g. input 3 is:
[[-1, -1, 1], [1, 1, -1]]

That is, -1-2+3, 1+2-3.

¹L can be ā for -1

Python 3, 105 bytes
lambda n:[k for k in product(*[(1,-1)]*n)if sum(-~n*s for n,s in enumerate(k))==0]
from itertools import*

Try it online!

Wolfram Language (Mathematica), 36 bytes
Pick[p={1,-1}~Tuples~#,p.Range@#,0]&

Try it online!

Husk, 10 bytes
fo¬ΣΠmSe_ḣ

Try it online!
Explanation
Not too complicated.
fo¬ΣΠmSe_ḣ  Implicit input, say n=4
         ḣ  Range: [1,2,3,4]
     m      Map over the range:
      Se     pair element with
        _    its negation.
            Result: [[1,-1],[2,-2],[3,-3],[4,-4]]
    Π       Cartesian product: [[1,2,3,4],[1,2,3,-4],..,[-1,-2,-3,-4]]
f           Keep those
   Σ        whose sum
 o¬         is falsy (equals 0): [[-1,2,3,-4],[1,-2,-3,4]]

JavaScript (V8),  69 61  58 bytes
Saved 8 bytes thanks to @Neil
Saved 3 bytes thanks to @l4m2
Prints all solutions.
f=(n,o='')=>n?f(n-1,o+'+'+n)&f(n-1,o+-n):eval(o)||print(o)

Try it online!

Do you need k? Something like this: f=(n,o='')=>n?['+','-'].map(c=>f(n-1,c+n+o)):eval(o)||alert(o)

@Neil I really don't... Thanks.

o+'-'+n => o+-n

Swift, 116 bytes
func f(n:Int){var r=[[Int]()]
for i in 1...n{r=r.flatMap{[$0+[i],$0+[-i]]}}
print(r.filter{$0.reduce(0){$0+$1}==0})}

Try it online!
Explanation
func f(n:Int){
  var r=[[Int]()]                         // Initialize r with [[]]
                                          // (list with one empty list)
  for i in 1...n{                         // For i from 1 to n:
    r=r.flatMap{[$0+[i],$0+[-i]]}         //   Replace every list in r with the list
  }                                       //   prepended with i and prepended with -i
  print(r.filter{$0.reduce(0){$0+$1}==0}) // Print all lists in r that sums to 0
}

Python 3 + numpy, 104 103 bytes
import itertools as I,numpy as P
lambda N:[r for r in I.product(*[[-1,1]]*N)if sum(P.arange(N)*r+r)==0]

Output is [-1, 1] corresponding to the sign.

You can remove the space before if for -1 byte

Python 2, 91 bytes
lambda x:[s for s in[[~j*[1,-1][i>>j&1]for j in range(x)]for i in range(2**x)]if sum(s)==0]

Try it online!
Returns a list of satisfying lists (e.g., f(3)=[[-1,-2,3], [1,2,-3]])

APL (Dyalog), 38 bytes
{k/⍨0=+/¨k←((,o∘.,⊢)⍣(⍵-1)⊢o←¯1 1)×⊂⍳⍵}

Try it online!

C (gcc), 171 161 bytes

Saved ten bytes thanks to ceilingcat.

k,s;f(S,n,j)int*S;{if(s=j--)S[j]=~0,f(S,n,j),S[j]=1,f(S,n,j);else{for(k=n;k;)s+=k--*S[k];if(!s)for(puts("");k<n;)printf("%d",S[k++]+1);}}F(n){int S[n];f(S,n,n);}

Try it online!

Pyth, 13 bytes
f!sT.nM*F_BMS

Try it here!

Clean, 79 bytes
import StdEnv
$n=[k\\k<-foldr(\i l=[[p:s]\\s<-l,p<-[~i,i]])[[]][1..n]|sum k==0]

Try it online!

Retina, 73 bytes
.+
*
_
=_$`
+0`=
-$%"+
(-(_)+|\+(_)+)+
$&=$#2=$#3=
G`(=.+)\1=
=.*

_+
$.&

Try it online! Explanation:
.+
*

Convert the input to unary.
_
=_$`

Convert the number to a list of =-prefixed numbers.
+0`=
-$%"+

Replace each = in turn with both - and +, duplicating the number of lines each time.
(-(_)+|\+(_)+)+
$&=$#2=$#3=

Separately count the number of _s after -s and +s. This sums the negative and positive numbers.
G`(=.+)\1=

Keep only those lines where the -s and +s cancel out.
=.*

Delete the counts.
_+
$.&

Convert to decimal.

C (gcc), 101 100 83 bytes
Represents addition as 0 and subtraction as 1, but that ultimately that does not matter since for any valid sequence, the complement of the sequence will also result in zero. Returns the permutations by appending them as 32-bit ints to a caller-provided buffer.
i,j,s;f(n,p)int*p;{for(i=1<<n;--i;s||(*p++=i))for(j=s=0;j<n;)s+=i>>j++&1?j:-j;n=p;}

Try it online!
Explanation
i,j,s; // iterators i and j, sum s.
f(n,p)int*p; // declare function
{
  for ( i=1<<n; --i; // iterate over all permutations of n bits (except all-0)
      s||(*p++=i)) // if the permutation summed to 0, append it to the buffer
   for(j=s=0;j<n;)
     s+= i>>j++&1 // Determine the value of the jth bit
       ?j:-j; // 1=>+(j+1), 0=>-(j+1)
  n=p; // return the pointer to the end of the appended values
}

I do not think you need to use any prettifiers for your output, which could save some bytes. Note that printf("\n") can often be replaced by puts("").

Ah, sorry, I misinterpreted the escape sequences' function. In that case, I think standard I/O also forbids your method since one normally thinks of bytes as a program's output, not its terminal appearance.

The general rule for this appears to be https://codegolf.meta.stackexchange.com/a/5515/46076, which I wasn't aware of until now. I've retracted my flag, since I honestly can't decide whether this answer is valid or not now. See also Default for Code Golf: Input/Output methods Also, fix ping to @JonathanFrech since the previous one didn't go through for me.

@pppery I also was not aware of this position, though as it appears to be consensus I guess that is the rule. Thank you for finding the meta post.

I have updated the function to use a buffer instead of stdout since other submissions return lists, etc. as well.

J, 35 30 bytes
-5 bytes thanks to FrownyFrog!
>:@i.(]#~0=1#.*"1)_1^2#:@i.@^]

Try it online!
Original:
J, 35 bytes
[:(#~0=+/"1)>:@i.*"1(_1^[:#:@i.2^])

How it works
I multiply the list 1..n with all possible lists of coefficients 1 / -1 and find the ones that add up to zero.
                    (             ) - the list of coefficients
                             i.     - list 0 to
                               2^]  - 2 to the power of the input
                     _1^[:          - -1 to the power of
                          #:@       - each binary digit of each number in 0..n-1 to
                 *"1                - each row multiplied by
            >:@i.                   - list 1..n
  (#~      )                        - copy those rows
     0=+/"1                         - that add up to 0
[:                                  - compose

Try it online!
As an alternative I tried an explicit verb, using the approach of cartesian product of +/-:
J, 37 bytes
3 :'(#~0=+/"1)(-y)]\;{(<"1@,.-)1+i.y'

{(<"1@,.-) finds the cartesian products for example:
{(<"1@,.-) 1 2 3
┌───────┬────────┐
│1 2 3  │1 2 _3  │
├───────┼────────┤
│1 _2 3 │1 _2 _3 │
└───────┴────────┘

┌───────┬────────┐
│_1 2 3 │_1 2 _3 │
├───────┼────────┤
│_1 _2 3│_1 _2 _3│
└───────┴────────┘

Too bad that it boxes the result, so I spent some bytes to unbox the values
Try it online!

@FrownyFrog Thank you, I was not happy with the right side of my code.

Perl 6, 43 bytes
{grep *.sum==0,[X] (1..$_ X*1,-1).rotor(2)}

Try it
Returns a sequence of lists
Expanded:
{  # bare block lambda with implicit parameter ｢$_｣

  grep              # only return the ones
    *.sum == 0,     # that sum to zero

    [X]             # reduce with cross meta operator

      (
          1 .. $_   # Range from 1 to the input

        X*          # cross multiplied by

          1, -1

      ).rotor(2)    # take 2 at a time (positive and negative)
}

1..$_ X* 1,-1 ⇒ (1, -1, 2, -2)
(…).rotor(2) ⇒ ((1, -1), (2, -2))
[X] … ⇒ ((1, 2), (1, -2), (-1, 2), (-1, -2))

Not the best but I tried :)
C (Linux GCC)
Entire program: 282 characters
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int n,x,i,s;int main(int c,char**z){n=atoi(z[1]);int a[n];for(x=0;x<n;x++)a[x]=x+1;for(i=0;i<pow(2, n)-1;i++){s=0;for(x=0;x<n;x++){printf("%c%d",i>>x&0x01?'-':'+',a[x]);s+=(i>>x&0x01?-1:1)*a[x];}printf(s!=0?"\r":"=%d \n",s);}}

Just as function: 196 characters
void z(int n){int a[n],x,i,s;for(x=0;x<n;x++)a[x]=x+1;for(i=0;i<pow(2,n)-1;i++){s=0;for(x=0;x<n;x++){printf("%c%d",i>>x&0x01?'-':'+',a[x]);s+=(i>>x&0x01?-1:1)*a[x];}printf(s!=0?"\r":"=%d \n",s);}}

Results

n = 4:

+1-2-3+4=0
-1+2+3-4=0

n = 7:

+1-2-3-4-5+6+7=0
-1+2-3-4+5-6+7=0
-1-2+3+4-5-6+7=0
+1+2-3+4-5-6+7=0
-1-2+3-4+5+6-7=0
+1+2-3-4+5+6-7=0
+1-2+3+4-5+6-7=0
-1+2+3+4+5-6-7=0

Abstract Printing & Just Function: 172 characters
You could shrink the print statements down much more by simply outputting only the +/-'s which are represented by 1/-1 and abstractly representing the entire sum thing, but I still don't think it would beat the other C answers anyway.
That version is:
void z(int n){int a[n],x,i,j,s;for(x=0;x<n;x++)a[x]=x+1;for(i=0;i<pow(2,n)-1;i++){s=0;for(x=0;x<n;x++){j=i>>x&0x01?-1:1;printf("%d ",j);s+=j*a[x];}printf(s!=0?"\r":"\n");}}

Results

n = 4:

1 -1 -1 1
-1 1 1 -1

n = 7:

1 -1 -1 -1 -1 1 1
-1 1 -1 -1 1 -1 1
-1 -1 1 1 -1 -1 1
1 1 -1 1 -1 -1 1
-1 -1 1 -1 1 1 -1 1
1 1 -1 -1 1 1 -1
1 -1 1 1 -1 1 -1 1
-1 1 1 1 1 -1 -1 -1

155 bytes

T-SQL, 152 bytes
Input is a varchar(max)
Output format is +1+2-3
WITH C as(SELECT @*1d,@+null o,0f
UNION ALL
SELECT~-d,concat(char(44+s),d,o),f+s*d
FROM C,(values(-1),(1))x(s)WHERE d>0)SELECT
o FROM C WHERE f=0and d=0

Try it online

R, 82 69 bytes
s=t(expand.grid(rep(list(c(-1,1)),n<-scan())))*1:n;t(s[,!colSums(s)])

Try it online!
Edit: -13 bytes by using built-in expand.grid function to automatically create matrix of all combinations of +1 and -1.
Selects rows of matrix of 1:n in all combinations of positive & negative which sum to zero.
Commented version:
s=t(                    # transpose matrix of:
mapply(rep,             # apply the function 'rep'
    list(c(-1,1)),      # to the values (-1, 1)
    each=2^(0:(n-1)),   # repeating each by an increasing power-of-2
    length=2^n)         # and making the output length always 2^n
)                       # so: this generates a matrix of all the
                        # combinations of -1 and 1

t(                      # now transpose the matrix s
s[,                     # taking only the columns with a
   !colSums(s*1:n)]     # zero sum of multiplying the values
)                       # by the sequence 1:n

Previous (but sadly longer much longer) recursive strategy: 118 bytes
f=function(n,l=NULL,t=0)`if`(n>1,c(f(n-1,c(0,l),t-n),f(n-1,c(1,l),t+n)),`if`(t==n,list(c(0,l)),if(t==-n)list(c(1,l))))

Try it online!
Outputs 1 for + and 0 for - (or the other way around).
Commented version:
f=function(n,l=NULL,t=0){               # n = counts down to 1 recursively
                                        # l = list of signs so far
                                        # t = total so far
    if(n==1){                           # if n is 1...
        if(t-n==0){                     # ...then if t-n makes zero...
            return(list(c("-",l))) }    # add a '-' to the list of signs & return it
        else if(t+n==0){                # ...or, if t+n makes zero...
            return(list(c("+",l))) }    # add a '+' to the list of signs & return it
        else {                          # ...otherwise we can't make zero...
            return(NULL) }              # so return NULL
    } else {                            # if n is greater than 1
        return(c(                       # return the result of calling this function
            f(n-1,c("-",l),t-n),        # using n-1, after applying either a '-'
            f(n-1,c("+",l),t+n)         # or a '+' and updating the total so far
        ))
    }
}

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Add TIO link to messages!
It's annoying when you have to search for a language homepage, get its link, and add it to your SE comment/answer, right? Let's write a script to do that for you!
Challenge
For each language name (intentional or not) in the input, replace it with the markdown link to the language home page, defined by TIO.
Rules

(important) You can only connect to https://tio.run.
Use the language list on TIO at the time your program is run.
The input is a string. Assume no newline (because multiline messages can't have markdown anyway). Unicode characters may be inside the string because they can exist in chat messages (example).
The input is valid markdown, but it is unlikely that this is related to the challenge.
You can assume there is no link inside the input. (Whoops, I missed this when the challenge was in the sandbox, thanks mercator for pointing that out. As far as I can see this should not invalidate any existing answers)
Case sensitive or insensitive, whatever you choose.
Only word breaks (not both adjacent to an English letter) are considered. (for example, matlab should not be converted to matlab, 47 should be converted to 47)

Note: It's too hard to define what's a "character" in Unicode, so your program can detect a word break or not if one of the two surrounding characters are not printable ASCII.

Only use markdown [...](...), not HTML link ... because the latter doesn't work in chat.
Markdown components (* / _ for italic, ** for bold, --- for strikethrough (in chat)) in messages should not matter, because AFAIK there are no languages with such names on TIO.
Use the language name (Wolfram Language (Mathematica)), not language ID.
No overlapping replacement.
In case there are multiple output, pick whichever. See example below.
Although by default chat markdown doesn't allow links in code blocks, for simplicity I would just assume that they don't need to be treated specially.

Winning criteria
code-golf.
Test cases
Input -> Output
matlab -> matlab
47 -> [4](https://github.com/urielieli/py-four)[7](https://esolangs.org/wiki/7)
/// -> [///](https://esolangs.org/wiki////)
//// -> [///](https://esolangs.org/wiki////)/ or /[///](https://esolangs.org/wiki////)
////// -> [///](https://esolangs.org/wiki////)[///](https://esolangs.org/wiki////) or //[///](https://esolangs.org/wiki////)/
Uṅıċȯḋė -> Uṅıċȯḋė

More test cases
(suggested by Adám. Any replacement is fine as long as they don't overlap (valid markdown source))
\///
S.I.L.O.S.I.L.O.S
Del|m|t
Del|m|tcl

"AFAIK there are no languages with such names on TIO" - congratulations, now there are going to be a dozen within a week because of this

Why can matlab not become [matl]ab but 47 can become [4][7]?

@HyperNeutrino Because word break.

Looks like people hate word breaks. I don't know. 2 downvotes already. [blame-sandbox]

@user202729 https://tio.run/##K6gsycjPM/7/PzO3IL@oRKEolaugKDOvRKMoVS8tMy8lMSdHo0gpJikmJSZJSUdBycRcSVPz/38A

@HyperNeutrino I told you, [blame-sandbox]. I don't know about the behavior of \b before asking, and now I can't invalidate answers.

matl isn't the name of a supported language. It's MATL. So the matlab test case doesn't cover the word break rule for answers that are case-sensitive.

And what should happen with input like a2sable or Ada (GNAT)foo? Are there word breaks at the start/end of those language names? And when you say the input is valid markdown, does this mean the input can also be a name that's already linked, like [4](https://en.wikipedia.org/wiki/4)? What should happen then?

@mercator Hopefully fixed? I don't understand, what's the problem with those inputs?

Looks good, yes. :) The problem with those inputs is I'm still not entirely sure what word breaks are. Is there a break in the middle of a2? The way it's described now seems to me like it's a word break if the language name is on the right (2), but not if the language is on the left (a). If there is a word break, none of the answers pass. And I'm wondering if I'm going to spend the effort trying to fix my answer. :P Or if I can convince you to drop the rule. ;)

@mercator But existing answers... I will test them (and probably change the rules accordingly) later.

Javascript (ES6) + jQuery, 247 bytes
s=>c=>$.getJSON('https://tio.run/static/645a9fe4c61fc9b426252b2299b11744-languages.json',data=>{for(l of Object.values(data))s=s.replace(eval(`/([^a-zA-Z]|^)${l.name.replace(/[\\/+.|()]/g,"\\$&")}(?![a-zA-Z])/g`),`$1[${l.name}](${l.link})`);c(s)})

Explanation (less golfed)
s=>c=>
// Load TIO languages using jQuery
$.getJSON('https://tio.run/static/645a9fe4c61fc9b426252b2299b11744-languages.json',data=>{
  // For every language
  for(l of Object.values(data)) {
    // Construct a regex that matches the language name
    var regex = eval(`/([^a-zA-Z]|^)${l.name.replace(/[\\/+.|()]/g,"\\$&")}(?![a-zA-Z])/g`
    // Replace all occurences of the language name with the language name and link
    s=s.replace(regex),`$1[${l.name}](${l.link})`)
  }
  // Return using callback
  c(s);
});

f=
s=>c=>$.getJSON('https://tio.run/static/645a9fe4c61fc9b426252b2299b11744-languages.json',data=>{for(l of Object.values(data))s=s.replace(eval(`/([^a-zA-Z]|^)${l.name.replace(/[\\/+.|()]/g,"\\$&")}(?![a-zA-Z])/g`),`$1[${l.name}](${l.link})`);c(s)})

f("47")(console.log);
f("///")(console.log);
f("////")(console.log);
f("//////")(console.log);
f("Uṅıċȯḋė")(console.log);
f("\///")(console.log);
f("S.I.L.O.S.I.L.O.S")(console.log);
f("Del|m|t")(console.log);
f("Del|m|tcl")(console.log);

Python + Selenium, 496 bytes
I decided using the front end of the website would be cooler.  And since nearly everything is loaded via JavaScript, Selenium was my best bet.
from selenium import webdriver
from re import*
d=webdriver.Chrome("a.exe")
d.get("https://tio.run/#")
t={e.text.lower():e.get_attribute("data-id")for e in d.find_elements_by_xpath('//*[@id="results"]/div')}
def q(reg):s=reg.group(0);d.get("https://tio.run/#"+t[s.lower()]);d.find_element_by_id("permalink").click();a=d.find_elements_by_tag_name("textarea")[4].get_attribute('value');return"["+s+"]("+search(': (ht.*)\n',a).group(1)+")"
print(sub('|'.join(map(escape,t.keys())),q,input(),flags=I))

Pseudo-Ungolfed Version
I thought providing an in-between would be useful for understanding.
from selenium import webdriver
import re
import itertools

input = lambda:"47////////"

s = input()
driver = webdriver.Chrome("chromedriver.exe")
driver.get("https://tio.run/#")
temp = {ele.text.lower():ele.get_attribute("data-id")for ele in driver.find_element_by_id("results").find_elements_by_tag_name("div")}
def abc(reg):
    s=reg.group(0)
    driver.get("https://tio.run/#"+temp[s.lower()])
    ele = driver.find_element_by_id("permalink").click()
    a = driver.find_elements_by_tag_name("textarea")[4].get_attribute('value')
    return"["+s+"]("+re.search(': (ht.*)\n',a).group(1)+")"
bob = re.sub('|'.join(map(re.escape,temp.keys())),abc,s,flags=re.I)
print(bob)

Python 2, 291 301 bytes
import json,urllib
s=raw_input().decode('u8');m=json.loads(urllib.urlopen('https://tio.run/languages.json').read());n=0
while n<len(s):
 for l in sorted(m,None,lambda x:m[x]['name'],1):
  L=m[l]['name'];r='[%s](%s)'%(L,m[l]['link'])
  if s.find(L,n)==n:s=s[:n]+r+s[n+len(L):];n+=len(r)-1
 n+=1
print s

Doesn't strictly speaking follow the rules, since it doesn't consider word breaks. It always takes the longest possible match first.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Is It Mountainous?
Challenge
For this challenge, a mountainous string is one that conforms to the grammar rule M: x(Mx)* where at each production, the all x's are the same character. When indented, a mountainous string might look something like this:
A
 B
  C
   D
  C
   E
    F
   E
  C
 B
A

As you can see, it looks a bit like a mountain from the side.
Formal Definition

Any single character a is mountainous.
If S is a mountainous string and a is a character, then aSa is mountainous, where juxtaposition represents string concatenation.
If aSa and aTa are mountainous strings, then aSaTa is a mountainous string. Note that this rule implies that this pattern holds for any number of repetitions. (i.e. aSaTaUa, aSaTaUaVa, aSaTaUaVaWa... are all mountainous.)

Examples
All odd-length palindromes are mountainous, for instance:
t
 a
  c
   o
  c
 a
t

qwertytrasdfdgdsarewqjklkjq is a less trivial example:
q
 w
  e
   r
    t
     y
    t
   r
    a
     s
      d
       f
      d
       g
      d
     s
    a
   r
  e
 w
q
 j
  k
   l
  k
 j
q

Example Outputs
a                           ==> true
aaa                         ==> true
mom                         ==> true
tacocat                     ==> true
qwertytrasdfdgdsarewqjklkjq ==> true
wasitacaroraratisaw         ==> true
abcbcbcbcba                 ==> true
aaaaabcbbba                 ==> true

<empty string>              ==> false
aa                          ==> false
pie                         ==> false
toohottohoot                ==> false
asdfdghgfdsa                ==> false
myhovercraftisfullofeels    ==> false

Rules

This is a decision problem, so any representation of true or false is valid output as long as it is correct, consistent, unambiguous, and the program terminates in a finite amount of time. Be sure to state your output convention with your solution.

It should be trivial to determine whether the output indicates true or false without having to know what the input string is. Note that this does not mean the truthy or falsy outputs have to be constant, however the convention of "print a mountainous string if the string is mountainous and a non-mountainous string if not mountainous" is a banned loophole for obvious reasons.
On the other hand, a convention like "throws an exception for false and exits silently for true" would be fine, as well as "prints a single character for true and anything else for false"

This is code golf, so the shortest program wins.
Standard loopholes are banned.

A test case like aaa would be good, where the same character needs to be used on multiple levels.

Are you sure about wasitacaroraratisaw ? It seems mountanous to me

wasitacaroraratisaw is indeed mountainous AFAICT

So it is. I guess I was just trying to find an 'almost palindrome', but I found a mountainous string by accident.

I thought this would be easy to solve by splitting the string on its first character, but cases like aaa make that not work.

You can solve it with a recursive descent parser. I believe a parser generator would also work.

Can we assume the input only contains lowercase ASCII characters?

I think something like abcdedfghgedcba should be in the falsey test cases (the second e would match the height of a preceding e during construction, but there is built mountain in the way, while if the second e were an f instead the string would be mountainous - or indeed if the f were an e).

"any representation of true or false is valid output as long as it is correct, consistent, and the program terminates in a finite amount of time." actually does not clearly define a line before a no-op ("returns a mountainous string when mountainous and not otherwise") which would clearly be a loophole. (note that "consistent" does not imply anything about being constant). I'd recommend requiring at least one of the two output sets to be singular as well as the outputs being consistent. (this is why using "truthy vs falsey" is easiest).

@Zgarb no. Even though I only use lowercase examples, it should work with all 8-bit strings. A lot of languages will handle unicode just fine, but I would rather hit the least common denominator. Whether it works or not for unicode does not matter.

@JonathanAllan "print the string for true and nothing for false" is fine. I see no reason for it to have to be constant. For instance, you could make it so the program throws an exception for true and does nothing for false. Or you could use return codes where 0 is true and nonzero is false. Or you can send out real missile alerts for true and test alerts for false. Whatever convention you want to use is fine as long as it's unambiguous.

Sure but my point was that at least one of the two outpurs should be required be fixed across runs, "print the string if true and nothing if false" fits that but "prints a mountainous string if true and not otherwise" does not and the latter allows a noop.

'the convention of "print a mountainous string if the string is mountainous and a non-mountainous string if not mountainous" is a banned loophole for obvious reasons.' As long as your convention isn't a copout in that same vein, it's allowed.

Japt v2, 14 13 bytes
e/.).\1/_g
¥g

Test it online!

Clean, 94 89 87 80 bytes
import StdEnv
?[a,b,c:s]=[a: ?if(a==c)s[b,c:s]]
?l=l
$s=limit(iterate?s)==[hd s]

Try it online!

Perl, 22 bytes
Includes + for p
perl -pe '$_=/^((.)((?1)\2)*)$/' <<< abcbcbcbcba

Prints 1 for true, nothing for false

Brain-Flak, 78 bytes
({()<<>(([{}]({}))([{}]({}))<>[({}<>)])>{[()()]((<()>))}<{}{}{}<>>}(())){{}}{}

Try it online!
Prints 1 for true, nothing for false.
To verify a mountainous word, it is sufficient to assume the word goes "down" the mountain whenever possible.

Prolog (SWI), 29 bytes
a-->[X],+X.
+X-->[];a,[X],+X.

Try it online!
This program defines a DCG rule a//0 that matches any string (list of characters) that is a mountainous string.
Explanation
For this program I use a slightly different but equivalent definition for mountainous strings than what is described in the challenge: A mountainous string is a character c followed by a number (could be zero) of mountainous strings with c tacked onto the ends of them. In a more terse regex derived notation, a mountainous string must match the pattern c(Mc)* where M is a mountainous string and * means that the expression in parentheses is repeated zero or more times. Note that while each c must be the same character, each M does not need to be the same mountainous string.
Proof of Equivalence
It is clear that rules 1 and 2 from the challenge are equivalent to my rule where Mc occurs zero and one times respectively.
In the case that the mountainous string has Mc occurring n times where n > 1 then the string can be rewritten as cMcSc where S is the latter n - 1 times that Mc occurs excluding the last c (note that M is any mountainous string and not necessarily the same as other M). Since M is a mountainous string, by rule 2, cMc must be a mountainous string. Either S is a mountainous string in which case cSc is a mountainous string or S can be rewritten as cMcTc where T is the latter n - 2 times that Mc occurs excluding the last c. This line of reasoning can keep on being applied until string not guaranteed to be mountainous contains Mc once which would mean it would have to be mountainous as well. Thus since cMc is mountainous and if cMc and cM'c are mountainous then cMcM'c must be mountainous the whole string must be mountainous.
For the converse, for a string cScTc where cSc and cTc are mountainous then either cSc is a mountainous string by rule 2 or by rule 3. If it is a mountainous string by rule 2 then S must also be a mountainous string. If it is a mountainous string by rule 3 then cSc must be of the form cUcVc where cUc and cVc are mountainous strings. Since the longer of cUc and cVc must still be at least two characters shorter than cSc and rule 3 requires at least 5 character to be applied then after a finite number of applications of rule 3 each string between the cs selected by applications of rule 3 must be a mountainous string. The same line of reasoning can be applied to cTc thus the string is mountainous by my definition.
Since any string that matches my definition is mountainous and my definition matches all mountainous strings, it is equivalent to the one given in the question.
Explanation of Code
Overall the a//0 DCG rule, defined on the first line, matches any mountainous string. The +//1 DCG rule (like predicates, DCG rules can be give operator names), defined on line two, matches any string that is made up of a sequence of zero or more mountainous strings with the character passed as its arguments X tacked onto the ends of them. Or to borrow the regex-like notation I used above, a//0 matches c(Mc)* but outsources the job of actually matching the (Mc)* to +//1 which takes c as its argument X.
Line by line the codes behaves as follows:
a-->[X],+X.

This line defines the DCG rule a. The [X] states that the first character must be equal to the currently undefined variable X. This results in X being set equal to the first character. The +X then states that the rest of the string must match the DCG rule +//1 with the character that X is set to as its argument.
+X-->[];a,[X],+X.

This line defines the +//1 DCG rule. The ; represents an or in Prolog which means that the string can match either [] or a,[X],+X. The [] represents the empty string so +//1 is always capable of matching the empty string. If the string is not empty then the start of it must match a//0 and so must be a mountainous string. This must then be followed by whatever character X is set to. Finally the rest of the string must match +X.

Python 2, 89 83 bytes
f=lambda s:re.search(M,s)and f(re.sub(M,r'\1',s))or len(s)==1
import re;M=r'(.).\1'

Try it online!
Thanks to ovs for 6 bytes.

Husk, 15 bytes
εωφΓ§?t·:⁰`(=←t

Try it online!
Type inference takes about 40 seconds, so be patient.
Explanation
εωφΓ§?t·:⁰`(=←t  Implicit input, say s = "abacdca"
 ω               Apply until fixed point is reached
  φ              this self-referential anonymous function (accessed with ⁰):
                  Argument is a string x.
   Γ              Deconstruct x into head h and tail t.
    §?t·:⁰`(=←t   Call this function on h and t. It is interpreted as §(?t)(·:⁰)(`(=←t)).
                  § feeds h to (·:⁰) and (`(=←t)), and calls (?t) on the results.
                  The semantics of ? cause t to be fed to all three functions.
          `(=←t   First, check whether h equals the first element (←) of the tail of t.
     ?t           If it does (e.g. if h='a' and t="bacdca"), return tail of t ("acdca").
                  Otherwise (e.g. if h='b' and t="acdca"),
       · ⁰        call the anonymous function recursively on t: "aca"
        :         and prepend h to the result: "baca".
                 Final result is "a".
ε                Is it a 1-element string? Implicitly print 0 or 1.

The idea is to repeatedly replace a substring of the form aba with a until this is no longer possible.
The input is mountainous if and only if this results in a single-character string (which is what ε tests).
The only dangerous situation is when we have a string like this, where aba doesn't seem to be a peak:
a
 b
  a
   c
  a
   d
  a
 b
a

Fortunately, we can always transform it into one:
a
 b
a
 c
a
 d
a
 b
a

I believe returning a single character for true cases and not otherwise would be "consistent".

Actually that may be pushing it, since there is no clear line between that and a no-op ("returns a mountainous string when mountainous and not otherwise") which would clearly be a loophole.

@JonathanAllan Single characters vs other strings seems a bit too fuzzy for me as well, especially since it has little relation to truthiness (only the empty string is falsy in Husk).

Yep the "any representation" is clearly too liberal - I have commented uner the OP :)

I actually want the definition to be liberal because it allows for more creative solutions. I changed the wording from 'consistent' to 'unambiguous', though I might also add that it should be unambiguous without context. As in, it should be clear without knowing what the input string was whether the result is true or false. So a single character for true and nothing for false would be fine.

Retina 0.8.2, 15 bytes
+`(.).\1
$1
^.$

Try it online! Trivial port of @ETHproductions' Japt answer.

JavaScript (Node.js), 53 bytes
I suppose this is nearly the most straightforward method to do so?
f=s=>(w=s.replace(/(.).\1/,"$1"))==s?w.length==1:f(w)

Try it online!
JavaScript (Node.js), 72 bytes
Less trivial one, but much longer.
s=>[...s].reduce((a,x)=>(a[a.length-2]==x?a.pop():a.push(x),a),[])==s[0]

Try it online!


text:
Friar simulator
The brethren from the order of St Golfus the Concise have a tradition of reciting a short prayer whenever they see someone make the sign of the cross. Due to the high level of sin measured among tourists recently, they have installed CCTV in the monastery, and they've hired you to help them keep old tradition alive in the age of AI.
Your task is to analyse output from the friars' finger-tracking software and tell how many prayers are due.
The input is a matrix containing integers between 0 and 4. 1,2,3,4 represent the positions of fingers at consecutive moments in time. 0 represents non-fingers.
The One True WayTM to cross oneself is:
.1.
3.4
.2.

("." matches any digit). However, due to uncertainty about the rotation of the camera and the presence of pious Eastern Orthodox brethren in the crowd (whose One True WayTM is in the opposite sideways direction), you should count all rotations and reflections too:
.4. .2. .3. .1. .3. .2. .4.
1.2 4.3 2.1 4.3 1.2 3.4 2.1
.3. .1. .4. .2. .4. .1. .3.

One digit may be part of multiple crosses.
Help the friars determine the number of times their AI should .pray() by counting how many of the above 3x3 submatrices are present. Write a program or a function. Take input in any reasonable convenient form.
Testament cases:
// in
[[0,4,2,0],
 [1,3,2,4],
 [2,3,1,0]]

// out
2

// in
[[4,3,3,2,4,4,1,3,2,2],
 [0,3,0,2,1,1,2,3,2,3],
 [0,3,1,3,2,4,3,3,1,1],
 [4,3,2,3,2,4,1,4,2,3],
 [0,4,2,3,4,0,2,3,2,4],
 [2,1,0,0,2,0,0,1,2,4],
 [4,0,3,1,3,2,0,3,2,3],
 [1,4,3,3,1,4,0,1,4,4],
 [0,2,4,3,4,3,1,3,0,4],
 [3,0,1,0,4,0,3,3,3,3]]

// out
3

// in
[[3,2,3,1,0,3,4,2,1,1,1,1,4,0,1,3,1,1,2,1,1,3,0,1,0,1,1,0,0,1,0,3,4,0,1,1,2,3,1,2,4,1,0,2,3,0,2,4,3,2],
 [2,4,1,1,0,3,0,2,4,2,3,2,1,3,0,2,3,2,4,4,4,3,2,1,1,3,2,1,2,3,2,4,0,3,1,4,4,1,1,0,1,1,0,2,2,3,1,2,0,2],
 [3,4,0,0,4,4,0,3,4,4,1,3,2,1,3,2,3,2,2,0,4,0,1,2,3,0,4,3,2,2,2,0,3,3,4,4,2,2,1,4,4,1,3,1,1,2,0,1,1,0],
 [1,4,2,2,2,1,3,4,1,1,2,1,4,0,3,2,2,4,1,3,3,0,4,1,1,0,0,1,2,2,1,3,4,0,4,1,0,1,1,0,2,1,3,1,4,4,0,4,3,2],
 [4,4,2,0,4,4,1,1,2,2,3,3,2,3,0,3,2,1,0,3,3,4,2,2,2,1,1,4,3,2,1,1,4,3,4,2,4,0,1,0,2,4,2,2,0,3,3,0,3,2],
 [4,3,3,1,3,1,1,3,3,1,0,1,4,3,4,3,4,1,2,2,1,1,2,1,4,2,1,1,1,1,1,3,3,3,1,1,4,4,0,0,3,3,1,4,4,3,2,3,3,0],
 [1,4,1,4,0,0,1,3,1,2,2,1,1,2,3,3,2,0,3,4,3,2,1,2,2,3,3,1,4,2,1,1,4,1,3,2,0,0,0,1,2,4,1,1,3,0,4,2,3,1],
 [2,2,3,0,0,4,2,1,2,3,1,2,4,1,0,1,0,2,4,1,3,4,4,0,0,4,0,4,4,2,0,0,2,2,3,3,4,1,0,3,2,1,0,1,1,0,3,0,3,2],
 [1,2,4,3,4,3,1,2,2,3,0,1,2,4,4,4,3,1,2,3,4,3,3,2,0,0,2,0,3,4,4,2,3,2,0,2,4,3,0,0,0,4,4,0,4,4,0,3,3,3],
 [4,4,1,2,0,2,2,0,0,3,2,3,2,3,4,1,0,2,3,0,3,2,1,1,4,3,0,2,3,1,0,4,1,2,4,1,1,4,4,4,2,2,2,3,0,1,0,3,0,1],
 [4,0,3,0,2,2,0,3,2,2,2,4,0,4,0,1,0,1,4,3,3,2,3,1,2,2,4,4,0,3,2,3,1,4,1,0,3,2,3,2,2,0,1,2,4,0,3,0,4,4],
 [0,4,0,1,0,2,3,2,1,3,1,1,2,0,3,2,1,4,0,1,4,4,1,3,4,4,1,0,4,1,0,3,4,0,3,2,4,3,3,3,3,1,2,2,3,3,3,1,3,4],
 [3,4,1,2,1,1,1,0,4,0,1,1,0,4,1,3,1,1,2,0,2,1,4,1,4,4,3,2,0,3,0,3,0,1,1,2,1,3,0,4,4,2,2,2,1,3,4,1,1,1],
 [3,0,1,4,2,0,0,3,1,1,1,4,4,0,2,2,0,4,0,3,1,0,2,2,4,4,4,0,4,4,4,4,4,4,3,0,4,4,4,1,2,4,4,3,0,0,4,0,4,2],
 [2,0,1,2,1,1,3,0,3,1,0,4,3,1,2,1,1,3,0,1,2,4,2,1,2,3,4,2,4,4,2,2,3,4,0,0,1,0,0,4,1,3,3,4,1,2,1,3,3,2],
 [4,0,2,0,3,1,2,1,1,1,1,2,3,0,3,1,0,4,3,0,0,0,2,0,1,4,0,2,1,3,4,2,2,4,2,3,1,2,0,2,0,2,4,0,1,2,3,4,1,3],
 [3,0,2,4,2,0,3,4,3,2,3,4,2,0,4,1,0,4,3,3,1,0,2,2,2,1,3,3,1,1,0,3,3,0,3,2,1,1,0,1,2,2,0,4,4,2,0,1,3,1],
 [0,4,4,4,0,3,0,3,0,2,2,0,1,2,3,3,4,3,0,4,1,2,3,3,0,2,2,3,0,0,0,2,4,2,3,4,2,3,4,0,2,0,1,1,3,4,2,2,4,4],
 [2,1,2,3,4,3,1,2,0,0,0,0,0,0,3,4,3,3,1,2,2,1,3,4,1,2,4,0,1,4,1,0,0,0,2,1,1,1,3,0,0,3,1,1,4,2,1,3,4,1],
 [1,0,3,0,2,1,4,2,3,3,1,1,3,4,4,0,1,2,1,3,0,3,1,1,3,0,2,4,4,4,2,3,1,4,3,4,0,1,4,1,1,1,4,0,0,2,3,4,0,4]]

// out
8

"Blessed be the shortest of shortests, for it winneth the kingdom of upvotes." -Book of St Golfus 13:37
"Thou shalt not use loopholes, for they are the wicked works of Lucifer." -Letter to the Meta 13:666
Slight visualization of people making the cross

var html = $('pre').html();
html = html.split('0').join('0')
.split('1').join('1')
.split('2').join('2')
.split('3').join('3')
.split('4').join('4')
$('pre').html(html);
var count =['zero','one','two','three','four'];
var counter = 0;
var $all = $('span');
window.setInterval(function() {
  var clazz = count[counter];
  counter++;
  if(counter == count.length) {
     counter = 0;
  }
  $all.css({'color':'white'});
  $('span.'+clazz).css({'color':''});

},1000)
.zero {
    color:blue;
}
.one {
    color:green;
}
.two {
    color:gray;
}
.three {
  color:orange;
}
.four {
  color: red;
}
span {
  transition:1s ease-out;
}

  // in
[[0,4,2,0],
 [1,3,2,4],
 [2,3,1,0]]

// out
2

// in
[[4,3,3,2,4,4,1,3,2,2],
 [0,3,0,2,1,1,2,3,2,3],
 [0,3,1,3,2,4,3,3,1,1],
 [4,3,2,3,2,4,1,4,2,3],
 [0,4,2,3,4,0,2,3,2,4],
 [2,1,0,0,2,0,0,1,2,4],
 [4,0,3,1,3,2,0,3,2,3],
 [1,4,3,3,1,4,0,1,4,4],
 [0,2,4,3,4,3,1,3,0,4],
 [3,0,1,0,4,0,3,3,3,3]]

// out
3

// in
[[3,2,3,1,0,3,4,2,1,1,1,1,4,0,1,3,1,1,2,1,1,3,0,1,0,1,1,0,0,1,0,3,4,0,1,1,2,3,1,2,4,1,0,2,3,0,2,4,3,2],
 [2,4,1,1,0,3,0,2,4,2,3,2,1,3,0,2,3,2,4,4,4,3,2,1,1,3,2,1,2,3,2,4,0,3,1,4,4,1,1,0,1,1,0,2,2,3,1,2,0,2],
 [3,4,0,0,4,4,0,3,4,4,1,3,2,1,3,2,3,2,2,0,4,0,1,2,3,0,4,3,2,2,2,0,3,3,4,4,2,2,1,4,4,1,3,1,1,2,0,1,1,0],
 [1,4,2,2,2,1,3,4,1,1,2,1,4,0,3,2,2,4,1,3,3,0,4,1,1,0,0,1,2,2,1,3,4,0,4,1,0,1,1,0,2,1,3,1,4,4,0,4,3,2],
 [4,4,2,0,4,4,1,1,2,2,3,3,2,3,0,3,2,1,0,3,3,4,2,2,2,1,1,4,3,2,1,1,4,3,4,2,4,0,1,0,2,4,2,2,0,3,3,0,3,2],
 [4,3,3,1,3,1,1,3,3,1,0,1,4,3,4,3,4,1,2,2,1,1,2,1,4,2,1,1,1,1,1,3,3,3,1,1,4,4,0,0,3,3,1,4,4,3,2,3,3,0],
 [1,4,1,4,0,0,1,3,1,2,2,1,1,2,3,3,2,0,3,4,3,2,1,2,2,3,3,1,4,2,1,1,4,1,3,2,0,0,0,1,2,4,1,1,3,0,4,2,3,1],
 [2,2,3,0,0,4,2,1,2,3,1,2,4,1,0,1,0,2,4,1,3,4,4,0,0,4,0,4,4,2,0,0,2,2,3,3,4,1,0,3,2,1,0,1,1,0,3,0,3,2],
 [1,2,4,3,4,3,1,2,2,3,0,1,2,4,4,4,3,1,2,3,4,3,3,2,0,0,2,0,3,4,4,2,3,2,0,2,4,3,0,0,0,4,4,0,4,4,0,3,3,3],
 [4,4,1,2,0,2,2,0,0,3,2,3,2,3,4,1,0,2,3,0,3,2,1,1,4,3,0,2,3,1,0,4,1,2,4,1,1,4,4,4,2,2,2,3,0,1,0,3,0,1],
 [4,0,3,0,2,2,0,3,2,2,2,4,0,4,0,1,0,1,4,3,3,2,3,1,2,2,4,4,0,3,2,3,1,4,1,0,3,2,3,2,2,0,1,2,4,0,3,0,4,4],
 [0,4,0,1,0,2,3,2,1,3,1,1,2,0,3,2,1,4,0,1,4,4,1,3,4,4,1,0,4,1,0,3,4,0,3,2,4,3,3,3,3,1,2,2,3,3,3,1,3,4],
 [3,4,1,2,1,1,1,0,4,0,1,1,0,4,1,3,1,1,2,0,2,1,4,1,4,4,3,2,0,3,0,3,0,1,1,2,1,3,0,4,4,2,2,2,1,3,4,1,1,1],
 [3,0,1,4,2,0,0,3,1,1,1,4,4,0,2,2,0,4,0,3,1,0,2,2,4,4,4,0,4,4,4,4,4,4,3,0,4,4,4,1,2,4,4,3,0,0,4,0,4,2],
 [2,0,1,2,1,1,3,0,3,1,0,4,3,1,2,1,1,3,0,1,2,4,2,1,2,3,4,2,4,4,2,2,3,4,0,0,1,0,0,4,1,3,3,4,1,2,1,3,3,2],
 [4,0,2,0,3,1,2,1,1,1,1,2,3,0,3,1,0,4,3,0,0,0,2,0,1,4,0,2,1,3,4,2,2,4,2,3,1,2,0,2,0,2,4,0,1,2,3,4,1,3],
 [3,0,2,4,2,0,3,4,3,2,3,4,2,0,4,1,0,4,3,3,1,0,2,2,2,1,3,3,1,1,0,3,3,0,3,2,1,1,0,1,2,2,0,4,4,2,0,1,3,1],
 [0,4,4,4,0,3,0,3,0,2,2,0,1,2,3,3,4,3,0,4,1,2,3,3,0,2,2,3,0,0,0,2,4,2,3,4,2,3,4,0,2,0,1,1,3,4,2,2,4,4],
 [2,1,2,3,4,3,1,2,0,0,0,0,0,0,3,4,3,3,1,2,2,1,3,4,1,2,4,0,1,4,1,0,0,0,2,1,1,1,3,0,0,3,1,1,4,2,1,3,4,1],
 [1,0,3,0,2,1,4,2,3,3,1,1,3,4,4,0,1,2,1,3,0,3,1,1,3,0,2,4,4,4,2,3,1,4,3,4,0,1,4,1,1,1,4,0,0,2,3,4,0,4]]

Thanks @Tschallacka for the visualization.

+1 for the verses at the end, they gave me a good laugh :D

Can one digit be part of multiple crosses?

@MartinEnder Yes. I'll edit that in.

Oh sweet Jesus, you did make a Friar simulator.

Why is the first “T” linked?

@JakeGould So as to link this question to the question the "T" leads to.

Grime, 20 bytes
n`.\1./\3.\4/.\2.voO

Try it online!
A very literal implementation of the spec:

n` make Grime count the number of subrectangles of the input that yield a match.
.\1./\3.\4/.\2. defines the 3x3 square:
.1.
3.4
.2.

Where . can be any character.
oO is an orientation modifier which allows this rectangle to appear in any rotation or reflection. The v is used to lower os precedence so that we don't need parentheses around the square.

Correct for the first two test, segfault for the last. I guess this should be ok as long as the program is correct in principle and is only limited by resources.

FYI: I just tested the last test case and it ran fine for me.

Snails, 17 16 bytes
Ao
\1.=\2o=\3b\4

Try it online!
Explanation
A makes Snails count the number of possible matching paths in the entire input. o sets the starting direction to any orthogonal direction (instead of  just eastward). The pattern itself is on the second line:
\1    Match a 1.
.     Match an arbitrary character (the one in the centre).
=\2   Check that the next character ahead is a 2, but don't move there.
o     Turn to any orthogonal direction. In practice, this will only be one
      of the two directions from the centre we haven't checked yet.
=\3   Check that the next character ahead is a 3.
b     Turn around 180 degrees.
\4    Match a 4 in that direction.

Perl, 70 bytes
Includes +2 for 0p
Give input matrix as a block of digits without spaces on STDIN:
perl -0pe '$_=map{/.$/m+y/1-4/3421/;/(?=1.{@{-}}(3.4|4.3).{@{-}}2)/sg}($_)x4'
0420
1324
2310
^D

Rotates the cross by rotating the digits

Haskell, 108 102 93 bytes
f((_:t:x):w@((l:q@(_:r:_)):(_:b:z):_))=sum$f((t:x):q:[b:z]):f w:[1|(l*r-1)*(t*b-1)==11]
f _=0

Try it online!
No regex. Pattern match
.t.
l.r
.b.

in the top left corner of the matrix , take a 1 if (l*r-1)*(t*b-1)==11 and recursively go to the right (drop .l.) and down (drop first row). If the pattern cannot be matched (at the right or bottom border) take a 0. Sum all results.
Edit: -9 bytes thanks to @xnor.

I was going to suggest 2^(l*r)+2^(t*b)==4100 to check the numbers, but it seems both our solutions are tricked by 2,6 in place of 3,4.

@xnor but the numbers are restricted to 0..4

@Οurous Thanks, I missed that. Then arithmetic expressions can be optimized even more, like (l*r-1)*(t*b-1)==11.

Retina, 92 83 82 bytes
L$v`(?<=(.)*).(.)..*¶(?<6-1>.)*(.).(.).*¶(?<-6>.)*.(.)
$5$2$3$4
/../_O`.
1234|3412

Try it online! Explanation:
L$v`(?<=(.)*).(.)..*¶(?<6-1>.)*(.).(.).*¶(?<-6>.)*.(.)
$5$2$3$4

Look for all overlapping 3x3 squares. A lookbehind captures the indent so that it can be balanced on the second line, itself transferring the indent from group 1 to group 6, so it can be balanced again on the third line. The input is assumed to be rectangular so we don't have to check that the groups balance. The bottom/top middle cells and the left/right middle cells are then captured.
/../_O`.

Sort each pair of cells into order.
1234|3412

Count the remaining valid patterns.

Jelly, 26 bytes
Z3Ƥṡ€3ẎµFḊm2ṙ-s2Ṣ€ṢFµ€ċ4R¤

Try it online!
Explanation
Z3Ƥṡ€3ẎµFḊm2ṙ-s2Ṣ€ṢFµ€ċ4R¤  Main Link
 3Ƥ                         For each 3 rows
Z                           Zip the rows
   ṡ€3                      Get all arrangements of 3 consecutive columns from these rows. At this step, we have all 3x3 contiguous submatrices
      Ẏ                     Unwrap by one layer; previously grouped by rows, now ungrouped
       µ           µ€       For each 3x3 submatrix
        F                   Flatten it
         Ḋ                  Get rid of the first element
          m2                Take every second element (this only keeps the edges)
            ṙ-              Rotate right 1 element
              s2            Group into pairs; now the top and bottom are grouped and the left and right are grouped
                Ṣ€          Sort each pair
                  Ṣ         Sort the pairs
                   F        Flatten
                      ċ4R¤  Count the number of occurrences of range(4); i.e. [1,2,3,4]

-3 bytes thanks to Jonathan Allan (2) and Mr. Xcoder (3) (merged)

@ngn lol the dot is meant to be under the D. My bad, fixed.

Save 2 bytes using ...Fµ€ċ4R¤ rather than ...Ḍµ€ċ1234 (also note that 1234 could have been replaced by ⁽¡ḋ to save one)

26 bytes by using Z3Ƥ instead of ṡ3Z€ and ⁼J$µ€S instead of Ḍµ€ċ1234.

@JonathanAllan oh cool, thanks

Java 8, 135 133 131 bytes
m->{int r=0,i=0,j;for(;++i<m.length-1;)for(j=1;j<m[i].length-1;)if(~(m[i-1][j]*m[i+1][j])*~(m[i][j-1]*m[i][++j])==39)r++;return r;}

-2 bytes thanks to @tehtmi for a shorter formula: (l*r-1)*(t*b-1)==11 to ~(l*r)*~(t*b)==39
Explanation:
Try it online.
m->{                     // Method with integer-matrix parameter and integer return-type
  int r=0,               //  Result-integer, starting at 0
      i=0,j;             //  Index integers
  for(;++i<m.length-1;)  //  Loop over the rows, skipping the first and last
    for(j=1;j<m[i].length-1;)
                         //   Inner loop over the columns, skipping the first and last
      if(~(m[i-1][j]*m[i+1][j])*~(m[i][j-1]*m[i][++j])==39)
                         //    If (-(bottom*top)-1) * (-(left*right)-1) is exactly 39:
        r++;             //     Increase the result-counter by 1
  return r;}             //  Return the result-counter

Shorter formula: ~(l*r)*~(t*b)==39 (Haskell doesn't have 1-byte ~ apparently.)

Husk, 23 bytes
#ö§&¦ḣ4SδΛ≈↔Ċ2tΣṁoX3TX3

Try it online!
Explanation
#ö§&¦ḣ4SδΛ≈↔Ċ2tΣṁoX3TX3  Implicit input, a list of lists of integers.
                     X3  Length-3 slices.
                ṁ        Map over them and concatenate:
                    T     Transpose,
                 oX3      then get length-3 slices.
                         Now we have a list of 3x3-arrays of the (transposed) input.
#ö                       Return number of 3x3-arrays that satisfy this:
                          Take m = [[0,3,0],[2,4,1],[1,4,0]] as an example.
               Σ          Concatenate: [0,3,0,2,4,1,1,4,0]
              t           Tail: [3,0,2,4,1,1,4,0]
            Ċ2            Take every second element: c = [3,2,1,4]
  §&                      c satisfies both of the following:
    ¦                     1) It contains every element of
     ḣ4                      the range [1,2,3,4].
       Sδ                 2) If you zip c
           ↔                 with its reverse,
         Λ                   then each corresponding pair
          ≈                  has absolute difference at most 1.
                         Implicitly print the result.

Python 3, 120 118 bytes
lambda x:sum({x[i+1][j]*x[i+1][j+2],x[i][j+1]*x[i+2][j+1]}=={2,12}for i in range(len(x)-2)for j in range(len(x[0])-2))

Try it online!
Uses the fact that the product of opposite pairs of numbers in the cross must be 2 and 12 respectively, and compares with a set to cover all the different orientations. Takes input as a 2D array of integers.

you don't have to count f= in the score

Dyalog APL, 30 29 28 27 26 bytes (SBCS)
+/∘,{12 2⍷×∘⌽⍨⊢/4 2⍴⍵}⌺3 3

Try it online!

very good! ⌽∘⊖×⊢ could be shorter by 2 bytes, can you guess how?

@ngn What I really want is a symbol like ø ;)

@ngn I have ×∘⌽∘⊖⍨

this is shorter: (⌽×⊖)

Oh, that's clever, you moved the selfie (...⍨) to left of ⊢/ for another -1. I didn't think of that. In this situation you shouldn't credit me.

Jelly, 36 bytes
“ƒɦƈạ%ȤFE’b4s4
ṡ3µZṡ3F€µ€ẎḊm2$$€’f¢L

Try it online!
37 bytes
For some reason I can't move the Ḋm2$$ to the top link.
ṙ1s2I€FPA,P⁼1,24
ṡ3µZṡ3F€µ€ẎḊm2$$€Ç€S

Try it online!

Clean, 255 ... 162 bytes
It isn't beneficial that often to use pattern filters in comprehensions, but in this case, it is.
import StdEnv,StdLib
? =reverse
@ =transpose
t=tails
$m=sum[1\\f<-[id,@,?,?o@,@o?,@o?o@,?o@o?o@,?o@o?],[a,b,c:_]<-t(f m),[_,1:_]<-t a&[3,_,4:_]<-t b&[_,2:_]<-t c]

Try it online!
Defines the function $, taking [[Int]] and returning Int.
It first generates all symmetries of the matrix m (transforming via f), takes the tails of which have three or more rows, and synchronously checks how many of the first three sets of columns from the tails of each row match the pattern of the cross.
This is equivalent to counting the number of ordered tails-of-tails matching the pattern [[_,1,_:_],[3,_,4:_],[_,2,_:_]:_] - which is in turn logically the same as checking if, for each cell in the matrix, that cell is the upper-left corner of any rotation of the cross.

Japt -x, 39 38 33 bytes
ã3 Ëmã3 y x@[XXy]®g1 ë2 ×Ãn e[2C]

Try it online!
-1 byte thanks to @Shaggy.
-5 bytes thanks to @ETHproductions by refactoring the array.
Unpacked & How it works
Uã3 mD{Dmã3 y xX{[XXy]mZ{Zg1 ë2 r*1} n e[2C]

       Input: 2D Array of numbers
Uã3    Generate an array of length 3 segments of U
mD{    Map... (D = 2D array of numbers having 3 rows)
Dmã3     Map over each row of D to generate an array of length 3 segments
y        Transpose; make an array of 3x3 subsections
xX{      Map and sum... (x = 3x3 2D array of numbers)
[XXy]      Array of X and X transposed
mZ{        Map...
Zg1 ë2 r*1   Take row 1, take 0th and 2nd elements, reduce with *
}
n          Sort the array
e[2C]      Equals [2,12] element-wise?
           Implicit cast from boolean to number

       Result: 1D array of counts
-x     Sum of the result array

There should still be a better way to test for the cross...

You can save a byte by replacing the equality check at the end with e[2C].

Can you get rid of the 2 in ë2?


text:
Get Two from One
As we saw in this question complex logical statements can be expressed in terms of the simple connectives of generalized Minesweeper.  However Generalized minesweeper still has redundancies.
In order to avoid these redundancies we define a new game called "Generalized-1 Minesweeper".
Generalized-1 Minesweeper is a version Minesweeper played on an arbitrary graph.  The graph has two types of vertex, an "indicator" or a "value".  A value can be either on or off (a mine or a dud) however its state is unknown to the player. An indicator tells that exactly one of the adjacent cells is on (a mine).  Indicators do not count as mines themselves.
For example the following board for Generalized Minesweeper tells us that cells A and B are either both mines or neither of them are mines.

(In the diagram indicators are marked in gray while values are white)
Unlike in normal minesweeper where you click values that are off to reveal indicators, there is no such mechanic in Generalized Minesweeper.  A player simply determines for what states of the graph can satisfy its indicators.
Your goal is to make a 2 in Generalized-1 Minesweeper.
You will build a structure in Generalized-1 Minesweeper such that there are 8 specific cells for which all possible configurations of values have exactly two cells on.  This means it behaves exactly as the 2 does in traditional minesweeper.  When you write your solution you should not have specific values in mind for value cells. (In answer to H.PWiz's question it is allowed that some value cells might be deducible from the state)
Scoring
You answers will be scored by the number of vertices in the final graph minus 8 (for the 8 inputs) with a lower score being better.  If two answers tie in this metric the tie breaker will be the number of edges.

Does any edge always connect an indicator vertex and a value vertex?

@xnor In order to maximize your score they ought, but I don't feel like I need to make that a rule.  Edges that don't connect values to indicators don't change the behavior of the graph.

When 6 is subtracted from the score, what are the 6 inputs? Aren't there 8 cells?

@xnor Sorry should be 8.  Fixed now.

What do you mean by "structure...such that there are 8 specific cells that the only possible configurations of values have exactly two cells on."? Are the only possible configurations supposed to have only two mines?

@dylnan You should be building a graph such that for 8 of its value cells (you choose which) exactly 2 of them must be mines, and any two of them can be mines.  The graph can have other helper value cells as well but we are only concerned with the behavior of 8 of the graph's cells.  Does that clarify?  I can help if you have any further specific questions.

Thanks, that does help. Is it required that any possible choice of two cells being mines (in the set of 8) satisfies the graph?

@dylnan Yes it is.

I'm not convinced that, in this case, you can always improve your score by removing such cells. This is certainly true when you can just change the indicator cell attached, but here there is only one kind of indicator cell

@H.PWiz You might be correct.  I'll see about verifying this fact but until then I will remove the comment.

@H.PWiz The only reason that can't be reduced is because you can deduce the value of the input cells.  I think that we can actually can remove deducible cells as long as they do not also deduce our input cells.

42 vertices, 56 edges

Each variable is a value vertex, and each box is an indicator vertex with edges to the variables inside it. The inputs are x1, ..., x8. For example, here's a solution with mines at x3 and x5, with mines highlighted in green.

The horizontal constraints ensure that exactly one of the a's and exactly one of the b's has a mine. In those two columns, r does not hold a mine, but it does in the other six columns. (Note that a and b can't both have a mine in the same column.) Each input x is opposite the r in its column, so exactly two inputs have mines as desired.
For k inputs, this uses 5k+2 vertices (3k value and 2k+2 indicator), and 7k edges. Here, k=8 inputs gives 42 vertices and 56 edges.

50 Vertices, 89 edges
Based on the logic gate from H.PWiz's answer.
  A&B      C&D      E&F      G&H
   |        |        |        |
b--1--a  d--1--c  f--1--e  h--1--g
|  |  |  |  |  |  |  |  |  |  |  |
1--?--1  1--?--1  1--?--1  1--?--1
|     |  |     |  |     |  |     |
A     B  C     D  E     F  G     H

Each * is on when the two respective inputs are on. To handle the case of a single input, we use the intermediate values a=A&!B etc. Connecting all three values a, b and A&B to the input of a secondary level of gates gives us an effective input of A|B (this saves vertices over !(!A&!B)):
      *              *
      |              |
   #--1--#        #--1--#
   |  |  |        |  |  |
   1--?--1        1--?--1
  |||   |||      |||   |||
  A|B   C|D      E|F   G|H

These *s are on if two of their inputs (corresponding to four of the original inputs) are on, except in the case of the pairs already covered above. Meanwhile, we can connect the #*# nodes to a final gate. We therefore have the following results:
A&B
C&D
E&F
G&H
(A|B)&(C|D)         [4 cases]
(E|F)&(G|H)         [4 cases]
(A|B|C|D)&(E|F|G|H) [16 cases]

These cover all 28 of the cases of two inputs. It then remains to connect a final indicator to these seven values. If fewer than two inputs are on, then none of these will be on, so the indicator will be off. If more than two inputs are on, then more than one of these will be on, and the indicator will be off.

Ah, I had similar idea, but ended up creating a more complicated version of this. Good job!

I'm not convinced that there are 43 vertices. You clearly show 42, so you're saying you only need one more to connect it all up?

Actually, if I have drawn correctly the graph you describe, I think it allows for states like ACE, BDF, ADG ...

@H.PWiz I see what you mean... I think maybe I can solve that with extra edges to give the expression (a&b)+((a|b)&(c|d))+(c&d)+((a|b|c|d)&(e|f|g|h))+(e&f)+((e|f)&(g|h))+(g&h)==1, does that look right to you?

Maybe, although to me that expression looks like it solves the problem entirely. And I have no idea what edges you can add to get that...

197 Vertices, 308 edges
I came up with this answer last night, but withheld posting it because it was such a high score. However, since it beats the other answer by so much, I though I should post it.
I use the following set up on all 28 pairs of values cells in ABCDEFGH
   ?*
   |
?--1--?
|  |  |
1--?--1
|     |
A     B

? represents an value cell not in ABCDEFGH. Here, when ?* is ON, A and B are both on. Otherwise, A and B could be in any other configuration.
I connect all 28 ?*s to one indicator cell. This means that only one pair in ABCDEFGH will have two ON. Which is sufficient to enforce that exactly two of my output cells will be ON

Note that in the gate you have each of the 4 ?s corresponds to one of the 4 states of A B.

@HeebyJeebyMan Interesting, I hadn't considered that. I just found this gate by luck

354 nodes, 428 edges
Just to prove it's possible. I will improve this later with some caching.
(hopefully no code error)
I tried to write a Mathematica program here to check program validity, but it doesn't work probably because there are too many variables.
The result was generated by computer program: Try it online!

I use a gate that looks like this:

               (f)
                |
                |
               (#)
              /   \
             /     \
           (d)     (e)
          /           \
         /             \
       (#) --- (c) --- (#)
     .'                  '.
   .'                      '.
(a)                          (b)

where (#) are 1-indicators, (a) .. (f) are values.
Then,

c = (not a) and (not b)
d = (not a) and      b
e =      a  and (not b)
f =      a  xnor     b

Also, this gate

(a) ----- (#) ----- (b)

gives

b = not a

. Use those two types of gates you can build any expressions.
Of course, this one is for asserting that (a) must be true:

(a) ----- (#)

81 Nodes, 108 Edges
Using 13 nodes and 14 edges, we create the following Adder gate (C(arry) = X AND Y, S(um) = X XOR Y):

X--1--------------?
   |              |
   ?--1--S--1--?--1
   |  |           |
   |  C           |
Y--1--------------?

Use four Adders M1, M2, M3, M4 to add A+B, C+D, E+F, G+H, respectively, with the resulting carry C1, C2, C3, C4, and sum S1, S2, S3, S4.
Use two Adders M5, M6 to add S1+S2, S3+S4, with the resulting carry C5, C6, and sum S5, S6.
Use one Adder M7 to add S5+S6 to get C7 and S7.
Now connect all carries to a single indicator node like the following:

C1-|
C2-|
C3-|
C4-+-1
C5-|
C6-|
C7-|

and force S7 (the modulo 2 of sum of 8 values) to be 0 by this circuit:

S7--1--?--1

I argue that this circuit forces exactly two values from ABCDEFGH to be ON, since it can only be an even number (since S7 is 0), and there cannot be more than 3 ON values (since only one of C1-C7 is ON).