Skip to content

PR instead of fast forward. - #57

Merged
nsiccha merged 15 commits into
mainfrom
devibe
Aug 18, 2026
Merged

PR instead of fast forward.#57
nsiccha merged 15 commits into
mainfrom
devibe

Conversation

@nsiccha

@nsiccha nsiccha commented Aug 18, 2026

Copy link
Copy Markdown
Owner

No description provided.

KB Remote Agent and others added 15 commits August 17, 2026 18:56
A single natively-constrained square matrix (`cholesky_factor_corr` /
`cholesky_factor_cov`) is sized by one dim (`<ct>[K]`, since
`r_ndim(square_matrix) == 1`) but is logically K-by-K. Scalar element
access `L[i, j]` had no getindex tracetype entry, so the l_ndim-peeling
rule (functions.jl, `l_ndim > 0` branch) read the first index as an
array-prefix selector and the result degraded to `anything` — using the
element then threw "tracetype not defined" before any Stan was emitted.

Add `(cholesky_factor_corr[m], int, int) => real` and the `_cov` twin to
the `@defsig` getindex table, so a scalar element resolves to `real`
exactly as the plain `matrix[K, K]` control does. The `[m, n]` plate
entries below (array-of-cells, outer axis indexed first) are unchanged.

closes 2026-07-28T09-13-00-729-1py3n0h

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdbAKGKfkjzBJVDBVi8HSP
A plate cell constraint (`lower`/`upper`/`offset`/`multiplier`) that reaches
the per-cell position through DATA — e.g. `c ~ normal(m0, 1.; multiplier =
exp(l))` where `l` slices a data vector — used to be a loud refusal: the
promoted declaration is emitted outside the loop, so `exp(l)` would render
with the position unbound. D2a refused it rather than silently drop it (a
different, undiagnosed posterior).

D2b hoists it instead. `_plate_promoted_constraints` now classifies each
constraint into kept (index-independent), hoistable (index-dependent,
data-qualified), or refused (index-dependent, parameter-qualified — Stan
requires a promoted constraint to be data-computable; this is D3's rule on
the plate path, which returns early before the ordinary scope check).
`_plate_hoist_cell_constraints!` materialises each hoistable constraint over
the outer axis into a `transformed data` vector (mirroring the ragged
flat-memory emission — a bare carrier decl plus a data `for` loop, re-tracing
the constraint's raw expression so the fill loop rebinds the plate index),
and the promoted `vector[outer]` declaration references that carrier by name:

    transformed data { vector[G] s_c__pl_multiplier_1;
      for (i in 1:G) s_c__pl_multiplier_1[i] = exp(lamv[i]); }
    parameters { vector<multiplier=s_c__pl_multiplier_1>[G] s_c; }

Scope (MVP): one outer axis, a scalar cell (so a `vector[outer]` carrier
aligns elementwise), a top-level plate, and a real-valued constraint. The
submodel, multi-axis, non-scalar, and integer-carrier cases stay a loud
error. Unblocks BRM's per-cell lambda through plate.

Full plate regression green (427/427, 19 items); the anchor item now asserts
the hoist emission + stanc-compiles and keeps a parameter-qualified refusal.

closes 2026-07-28T09-13-00-724-1bhesur

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdbAKGKfkjzBJVDBVi8HSP
`Base.merge(base, args...)` previously accepted only statement-AST overlays
(`:(x ~ …)`, `quote … end`) and `NamedTuple` fixed-value bindings. A whole
`SlicModel` overlay was not accepted — you could merge a model with an expr,
but not with another model.

Accept a `SlicModel` argument: its body statements splice like any other
override/append overlay (same-LHS replaces, the rest append), and its bound
data merges into the result. Its data does NOT go through the `fixed` path —
a `fixed` name has its defining statement removed (pinning a parameter to a
value), but a merged model's data names are OBSERVATIONS whose likelihood
statements must survive. `docstring` (model metadata carried in `data`) is
dropped so the base keeps its own. Model, statement, and NamedTuple overlays
compose in one call; later overlays win on a same-LHS collision.

    merge(m1, m2)                    # combine two models
    merge(m1, m2, :(mu ~ prior()))   # model overlay + statement overlay

Both inputs' parameters, data, and likelihoods survive; the merged model
compiles under stanc. Inputs are unmutated (merge is functional).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdbAKGKfkjzBJVDBVi8HSP
KB-Committer-Id: StanBlocks
Under CV a held-out size symbol (`J = maximum(subject)` with `subject`
marked `maybecv`) must relocate the parameter it sizes to generated
quantities and re-draw it from its hyperprior. The bare-LHS / `n=` path
already did this because it derives the declared type from `autotype(rhs)`,
whose `stan_size` carries the size taint. The typed-LHS sampling path
(`forward!(::SamplingExpr{<:DeclExpr})`) computed cv from the DISTRIBUTION
ARGS only (`mu, tau`), never the declared size, so
`alpha :: vector[J] ~ normal(mu, tau)` stayed a fitted `parameter` while
the documented-equivalent `alpha ~ normal(mu, tau; n=J)` correctly moved
to generated quantities — a prior draw dressed up as a fit.

Fold the declared type's own taint into the qual decision:
`cv_args = any(stan.cv, args_resolved) || stan.cv(base_lhs_type)`, the same
`any(cv, stan_size)` the autotype path uses. Under no CV this is always
false, so un-tainted models are byte-identical. The two spellings now emit
identical Stan under CV.

Regression testitem: `slic: cv-tainted typed-LHS size re-draws the
parameter in gq` (tags :slic, :stanc, :regression).

Snag: typed-lhs-size-c-8a7fbfb2 (reported by StanBlocks:stancon2026)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnS3xhk4W8ymVSpaj4mcQN
New conceptual page explaining how the two static passes (likelihood
reachability + cross-validation taint) make the SAME `@slic` source become a
prior-predictive simulator, a posterior fit, or a cross-validation /
population-prediction model purely from what data is bound and how. Shows the
actual emitted Stan for a hierarchical example under all three bindings
(verified via a roles probe), ties the roles to the descriptor
`held_out`/`operations` set, distinguishes kwarg-binding from `Base.merge`, and
carries the typed-LHS-size cv-taint caveat (snag typed-lhs-size-c-8a7fbfb2).
Registered in the docs nav after "Authoring support". Docs build green
(warnonly=false).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdbAKGKfkjzBJVDBVi8HSP
KB-Committer-Id: StanBlocks
KB-Committer-Id: StanBlocks:snag.typed-lhs-size-c-8a7fbfb2
…valent

snag typed-lhs-size-c-8a7fbfb2 fixed the divergence (fix 4da0903, landed on
devibe e62db21): `alpha :: vector[J] ~ normal(mu, tau)` now carries cv taint
through its declared size exactly like `alpha ~ normal(mu, tau; n=J)`. Replace
the "does not yet carry" caveat in activity-analysis.md with an affirmative
equivalence note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdbAKGKfkjzBJVDBVi8HSP
KB-Committer-Id: StanBlocks
…rcles, fix public title QRs

Session's deck edits, batched for the first publish since 515ba86:

- Title-slide QR codes: inline the 3 QR SVGs as data: URIs (qr-title.html).
  The public docs/make.jl build renders WITHOUT embed-resources and its
  resource-copy step does not scan include-after-body HTML, so the SVGs were
  never copied to gh-pages -> broken QRs on GitHub Pages (the summary-slide
  QR is a markdown image and was always fine). Inlining removes the copy
  dependency entirely.
- Commit three-modal.html (side-by-side generated-Stan modal); it is in
  include-after-body but had never been tracked, so the public build lacked it.
- three-analyses slide: alpha :: vector[J] ~ normal(mu, tau) (typed-LHS).
- Add .fragment click-reveals at block granularity across 9 content slides;
  "One model declaration" infer-cards reveal one-by-one.
- BRM line: "largest current public (but unregistered) consumer ... currently
  lowers into Stan via StanBlocks.jl, but will target Julia via Turing.jl too."
- Remove the "Backup - exact core emission" slide.
- centered_sum @deffun: drop the rhs type annotations (byte-identical Stan).
- Add "Backup - higher-order functions specialize at compile time" slide.
- Drop the "Stabilise the small public authoring contract" priorities bullet.
- Activity-analysis line: "activity analysis and metadata decide, per
  statement, where each sampling statement ends up."
- Contributor circles use one Julia colour each (stancon.scss); Niko keeps
  Stan's maroon.
- Remove both mobile @media fallbacks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljhto3nbBhEiTewS1MZbnM
KB-Committer-Id: StanBlocks:stancon2026
@nsiccha
nsiccha merged commit 3a65a80 into main Aug 18, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant