How to always have a multiple of 4 pages - pagecount, pagebreaks in context block and footer behaviour

Although there is already a similar question posted here, I’m curious about the behaviour of this piece of typst code.

The goal is to have always a total number of pages thats a multiple of 4, but i have weird behaviour that i don’t understand.

First, here is my sample code:

#let config = (number-of-content-pages: 0, round-up-to-multiple-of: 4, include-weird-content: false)
// unpacking
#let (number-of-content-pages, round-up-to-multiple-of, include-weird-content) = config



// setup

#set page(
  paper: "a5",
  footer: context [
    #set align(center)
    #counter(page).display(
      "1",
    )
  ]
)

// title page

= Titlepage (Page 1)

// generate n content pages

#for _ in range(number-of-content-pages) {
  [
    #pagebreak()
    = Contentpage (Page #context here().page())
    
  ]  
}


// round up to multiple of 4

#context {
  let page-count = here().page()
  // let page-count = counter(page).get().at(0)
  let additional-pages = calc.rem-euclid(round-up-to-multiple-of - page-count, round-up-to-multiple-of)

  for _ in range(additional-pages) {

    if include-weird-content {
      " "  
    }
    
    pagebreak()
    [additional page  \ \ page count: #page-count \ additional pages: #additional-pages]
  }
}

1. using as is:

#let config = (number-of-content-pages: 0, round-up-to-multiple-of: 4, include-weird-content: false)

This results in 3 total pages, because the page-count value is somehow 2.

1.1. Include weird content fixes the problem:

#let config = (number-of-content-pages: 0, round-up-to-multiple-of: 4, include-weird-content: true)

Now we include the weird content and magically the page count is right and the total number of pages is 4.

2. Usually, we have content pages:

#let config = (number-of-content-pages: 2, round-up-to-multiple-of: 4, include-weird-content: false)

The total number of pages is 4, which is great! But now the footer of the additional page (last one) shows page number 1

2.1 Again, including weird content fixes the problem: (content-pages: 2, round_up_to: 4, include-weird-content: true)

#let config = (number-of-content-pages: 2, round-up-to-multiple-of: 4, include-weird-content: true)

Why is this behaving like it is?

Point 1 is caused by what @Eric explained in the post you linked: How to always have a multiple of four as the number of pages - #4 by Eric

You can see it if you uncomment and comment the highlighted line in this simplified example:

#set page(paper: "a7")
#context {
  let num = here().page()
  // "" // <- here
  pagebreak()
  [#num]
}

Point 2 is caused by Typst not finding a stable document state in the 5 layout iterations it has available caused by Point 1. That’s also why you get the warning “Layout did not converge within 5 attempts”.
To get insights on what he compiler does in the 5 iterations, you can play around with layout-ltd.

#import "@preview/layout-ltd:0.1.0": layout-limiter
#show: layout-limiter.with(max-iterations: 1)

// your code here

This feels cursed.

So I learned two things:

  1. Context location is anchored at the first element in the context
  2. typst runs on a document till the document converges, in this case it oscillates so it fails.

Two more questions arise:

  1. Why doesn’t this: #context here().page() work at all? As there is no element in this context?
  2. Why does context need an explicit element for this? Why did typst choose to design it like this?