From d3421b3041f06d1eca8b549f6aaa246dff5cde7a Mon Sep 17 00:00:00 2001 From: EiffL Date: Sun, 5 Jul 2026 18:56:35 +0200 Subject: [PATCH] Add /lc-report skill: author MyST reports referencing astra.yaml by path The removed narrative field (PR #156, astra-spec RFC-0002) is replaced by external MyST reports resolved by the MySTRA plugin; lc init now scaffolds the template (PR #157). This adds the authoring skill that teaches the agent to build those reports, and wires it through the bundle. - New lc-report skill: golden rule (reference, never restate), setup, three modes (paper reproduction / co-drafting / retrofit), structure, draft order, and a myst-build validate loop. References carry the full MySTRA syntax, the prose-craft discipline ported from the retired narrative skill, and reproduction-mode fidelity rules. - lc-from-paper REVIEW: authoring the MyST report is now a close-out step (Step 4); outputs, survey signals, and phase table updated. - lc-new (Done) and lc-from-code (Phase 3) point at /lc-report. - astra reference: Description section notes write-ups live in external reports. - session-start primer: drop stale "narrative anchors", add /lc-report. - Project CLAUDE.md templates (inline + bundled) and the lc init index.md stub mention /lc-report; bundled template gains the missing Report section. - Docs: skills mirror page, nav entry, index rows, agent-workflow section. Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 2 +- claude/lightcone/scripts/session-start.sh | 7 +- claude/lightcone/skills/README.md | 1 + claude/lightcone/skills/astra/SKILL.md | 2 + claude/lightcone/skills/lc-from-code/SKILL.md | 2 + .../lightcone/skills/lc-from-paper/SKILL.md | 4 +- .../skills/lc-from-paper/references/review.md | 24 +- claude/lightcone/skills/lc-new/SKILL.md | 2 + claude/lightcone/skills/lc-report/SKILL.md | 106 +++++++++ .../skills/lc-report/references/craft.md | 49 ++++ .../lc-report/references/mystra-syntax.md | 210 ++++++++++++++++++ .../references/paper-reproduction.md | 59 +++++ claude/lightcone/templates/CLAUDE.md | 9 + docs/skills/index.md | 2 + docs/skills/lc-report.md | 93 ++++++++ docs/user/agent-workflow.md | 31 ++- src/lightcone/cli/commands.py | 6 +- zensical.toml | 1 + 18 files changed, 592 insertions(+), 18 deletions(-) create mode 100644 claude/lightcone/skills/lc-report/SKILL.md create mode 100644 claude/lightcone/skills/lc-report/references/craft.md create mode 100644 claude/lightcone/skills/lc-report/references/mystra-syntax.md create mode 100644 claude/lightcone/skills/lc-report/references/paper-reproduction.md create mode 100644 docs/skills/lc-report.md diff --git a/CLAUDE.md b/CLAUDE.md index 52ff90f0..07d8856f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -68,7 +68,7 @@ src/lightcone/ # namespace — NO __init__.py claude/lightcone/ # Claude plugin source — force-included into the wheel ├── skills/ # lc-new, lc-from-code, lc-from-paper, -│ # lc-feedback, ralph; +│ # lc-report, lc-feedback, ralph; │ # paper-reproduction bundle: lc-from-paper (entry), │ # ralph (loop substrate), │ # paper-extraction, figure-comparison, diff --git a/claude/lightcone/scripts/session-start.sh b/claude/lightcone/scripts/session-start.sh index 121f7c9f..e54e853c 100755 --- a/claude/lightcone/scripts/session-start.sh +++ b/claude/lightcone/scripts/session-start.sh @@ -54,8 +54,11 @@ Substrate CLIs (use --help on any): astra validate / astra paper add / astra universe generate Reference skills (invoke when the surface above isn't enough): - /astra — astra.yaml spec: decisions, prior_insights, findings, evidence, sub-analyses, narrative anchors - /lc-cli — lc workflow: spec-code invariant, status interpretation, failure diagnosis" + /astra — astra.yaml spec: decisions, prior_insights, findings, evidence, sub-analyses, composition + /lc-cli — lc workflow: spec-code invariant, status interpretation, failure diagnosis + +Report authoring: + /lc-report — draft/extend the MyST report (index.md): references spec elements by path, never hard-types results" if [ "$validation_ok" -ne 0 ]; then # tail rather than head -- the leading lines are success markers diff --git a/claude/lightcone/skills/README.md b/claude/lightcone/skills/README.md index 5501fdda..855185ba 100644 --- a/claude/lightcone/skills/README.md +++ b/claude/lightcone/skills/README.md @@ -9,6 +9,7 @@ Each subdirectory is one Claude Code skill: `SKILL.md` plus optional `references | `lc-new` | Scaffold a new ASTRA-shaped project from a research question. | | `lc-from-code` | Bring an existing codebase into ASTRA — scan, spec, parameterize. | | `lc-from-paper` | Reproduce a published paper in ASTRA (paper-reproduction bundle entry point — see below). | +| `lc-report` | Author the project's MyST report — the external write-up that references `astra.yaml` elements by tree-path via the MySTRA plugin. Invoked standalone ("write up the results") and from `lc-from-paper`'s REVIEW close-out. | | `lc-feedback` | Report bugs and feature requests upstream. | | `ralph` | Author a constitution and run a ralph loop against it (authoring + launching + iterating in one skill). `lc-from-paper` uses this for the long middle of a reproduction; standalone for any other long-running work. | diff --git a/claude/lightcone/skills/astra/SKILL.md b/claude/lightcone/skills/astra/SKILL.md index 51430183..29b047c9 100644 --- a/claude/lightcone/skills/astra/SKILL.md +++ b/claude/lightcone/skills/astra/SKILL.md @@ -357,6 +357,8 @@ The **`universe:` field** in universe files selects which sub-analysis universe Per-element prose (what each Input, Output, Decision, Option, or Insight is and why) belongs on the elements themselves via `description`/`rationale`/`notes` -- those can be written from day one. The analysis-level `description` can be filled in at any time and is safe to leave short. +Rich write-ups do not live in the spec at all: they are external MyST reports that reference analysis elements by tree-path (the `/lc-report` skill authors them; `lc init` scaffolds the template). + ```yaml description: | A two-stage pipeline for Iris classification that demonstrates diff --git a/claude/lightcone/skills/lc-from-code/SKILL.md b/claude/lightcone/skills/lc-from-code/SKILL.md index f81ac86f..8e372f8f 100644 --- a/claude/lightcone/skills/lc-from-code/SKILL.md +++ b/claude/lightcone/skills/lc-from-code/SKILL.md @@ -122,6 +122,8 @@ If the scan found existing results elsewhere in the project, compare them agains Then validate the spec and the provenance chain: `astra validate astra.yaml` and `lc verify`. Present summary to user. +With outputs materialized, offer to draft the write-up: `/lc-report` authors the project's MyST report (`index.md`), referencing the freshly specced decisions and outputs by path. + ## Rules - **Minimal changes.** Do not refactor, rename, reorganize, or "improve" existing code. diff --git a/claude/lightcone/skills/lc-from-paper/SKILL.md b/claude/lightcone/skills/lc-from-paper/SKILL.md index b48c1c65..fe26ca7e 100644 --- a/claude/lightcone/skills/lc-from-paper/SKILL.md +++ b/claude/lightcone/skills/lc-from-paper/SKILL.md @@ -42,7 +42,7 @@ Eight phases (zero-indexed). ORIENT runs before the loop, in the user's main ses | 4 | IMPLEMENT | ralph iteration | [`references/implement.md`](references/implement.md) | `scripts/`, `requirements.txt`, recipes in `astra.yaml` | | 5 | RUN | ralph iteration | [`references/run.md`](references/run.md) | `results///` | | 6 | COMPARE | ralph iteration | [`references/compare.md`](references/compare.md) | `comparison-report.{yaml,md}` | -| 7 | REVIEW | user's main session | [`references/review.md`](references/review.md) | `REPRODUCTION-SUMMARY.md`, `/figure-comparison` HTML, resolved `open-questions.md`, finalized reproduction outcome | +| 7 | REVIEW | user's main session | [`references/review.md`](references/review.md) | `REPRODUCTION-SUMMARY.md`, `/figure-comparison` HTML, resolved `open-questions.md`, MyST report (`index.md` via `/lc-report`), finalized reproduction outcome | COMPARE produces a verdict plus an opportunity assessment — not just pass / fail, but where the gaps are, how much they likely matter, and how they sit relative to the constitution's fidelity intent. A subsequent iteration decides whether to spend another IMPLEMENT round (close a gap that sits below intent) or land the reproduction at its current trajectory and log the gap into CLAUDE.md's Open opportunities. Once the COMPARE → IMPLEMENT loop terminates (verdict `pass`, or `partial` with the un-acted opportunities logged), a subsequent cold-survey iteration finds nothing left to do and flips the constitution's `status:` to `closed`. The loop terminates; REVIEW runs in the user's main session. @@ -120,7 +120,7 @@ Each iteration's survey reads the workdir to determine what phase is next. File ## REVIEW close-out (after the loop) -When the loop closes (the user reports back that the tmux session has exited, or `constitution.md`'s `status:` is `closed`), run REVIEW from the user's main session. See [`references/review.md`](references/review.md) for the full close-out: invoke `/figure-comparison` (mandatory) and optionally `/check-sentence-by-sentence`, walk `open-questions.md` with the user, draft `REPRODUCTION-SUMMARY.md`, propagate un-acted opportunities into CLAUDE.md, commit. +When the loop closes (the user reports back that the tmux session has exited, or `constitution.md`'s `status:` is `closed`), run REVIEW from the user's main session. See [`references/review.md`](references/review.md) for the full close-out: invoke `/figure-comparison` (mandatory) and optionally `/check-sentence-by-sentence`, walk `open-questions.md` with the user, draft `REPRODUCTION-SUMMARY.md`, author the MyST report via `/lc-report`, propagate un-acted opportunities into CLAUDE.md, commit. REVIEW runs in your main session because `/figure-comparison` and `/check-sentence-by-sentence` both use `AskUserQuestion`, which isn't available inside ralph iterations. diff --git a/claude/lightcone/skills/lc-from-paper/references/review.md b/claude/lightcone/skills/lc-from-paper/references/review.md index 5a080bf7..3e9cd06d 100644 --- a/claude/lightcone/skills/lc-from-paper/references/review.md +++ b/claude/lightcone/skills/lc-from-paper/references/review.md @@ -2,7 +2,7 @@ The reproduction has converged: the constitution's `status:` is `closed` (after COMPARE returned `pass`, or `partial` with the un-acted opportunities logged, and the next cold-survey iteration found nothing left to do). The ralph loop's tmux session has exited. REVIEW runs back in the user's main session — the second of two interactive bookends, the first being ORIENT. It runs in the user's main session (not as an iteration) because both `/figure-comparison` and `/check-sentence-by-sentence` use `AskUserQuestion`, which isn't available inside detached ralph iterations. -Its job is to render the validation surfaces, walk the user through the accumulated open questions, land the resolutions, and draft the final report — in one interactive arc. The Open opportunities list in CLAUDE.md already carries un-acted-on opportunities from the latest COMPARE (those iterations logged them directly); REVIEW just reads them. +Its job is to render the validation surfaces, walk the user through the accumulated open questions, land the resolutions, and draft the final summary and MyST report — in one interactive arc. The Open opportunities list in CLAUDE.md already carries un-acted-on opportunities from the latest COMPARE (those iterations logged them directly); REVIEW just reads them. The phase name **REVIEW** is freed by the old pre-implement REVIEW phase folding into ARCHITECT, SPECIFY, LITERATURE, and IMPLEMENT as their per-iteration self-review passes. This close-out is what the previous shape called SUMMARIZE_RUN. @@ -24,7 +24,8 @@ The phase name **REVIEW** is freed by the old pre-implement REVIEW phase folding - (Optional) `.lightcone/check-sentence-by-sentence.md` — `/check-sentence-by-sentence`'s claim audit (file:line or NOT FOUND per sentence) - `open-questions.md` — same file, but with `## Resolutions` section appended capturing what the user said for each entry - Edits to `astra.yaml` / `implementation-notes.md` / `universes/baseline.yaml` if any open-question resolution warrants a spec change -- `REPRODUCTION-SUMMARY.md` — final report; concise (~1–2 pages); the canonical record of what the reproduction landed on +- `REPRODUCTION-SUMMARY.md` — final summary; concise (~1–2 pages); the canonical record of what the reproduction landed on +- `index.md` + `myst.yml` — the MyST report, authored via `/lc-report`: the rich, publication-shaped write-up that references `astra.yaml` elements by path - CLAUDE.md updates — **Paper-vs-code disagreements** entries reconciled with their resolutions (Open opportunities already there from COMPARE iterations) - A commit closing out the reproduction @@ -74,13 +75,21 @@ A single markdown file at the project root, ~1–2 pages. The canonical record o Brief, not exhaustive. The depth lives in `astra.yaml` and the workdir's notes; the summary is the door into them. -## Step 4: reconcile the Open opportunities list +## Step 4: author the MyST report with `/lc-report` + +`REPRODUCTION-SUMMARY.md` is the concise close-out record; the MyST report is the rich, publication-shaped companion — Introduction / Methods / Results prose that references the spec's decisions, findings, and outputs by path and pulls reproduced numbers in live, so it can never drift from what the pipeline actually produced. + +Invoke `/lc-report` in paper-reproduction mode. It reads the spec, `work/reference/`, the comparison verdict, and the open-question resolutions from Step 2 — the divergence passages ("during reproduction we found…") come straight from those resolutions. If `index.md` / `myst.yml` don't exist yet (reproduction workdirs typically weren't scaffolded by `lc init`), the skill creates them. It validates with `myst build --html` before finishing; show the user how to preview (`myst start`). + +If the user prefers to skip the report, log it as an Open opportunity in CLAUDE.md instead of silently dropping it. + +## Step 5: reconcile the Open opportunities list COMPARE iterations have been logging un-acted-on opportunities into CLAUDE.md's *Open opportunities* list as they run, so the list is already populated. REVIEW's job here is reconciliation: cross-check that every opportunity in `comparison-report.yaml`'s `opportunities:` block that the user did NOT act on is present in CLAUDE.md's list, and remove any that the user acted on at REVIEW (e.g. authorized one more IMPLEMENT round to close). -## Step 5: commit +## Step 6: commit -Stage `REPRODUCTION-SUMMARY.md`, `open-questions.md` (with resolutions), the updated CLAUDE.md, the final `astra.yaml`, the comparison artifacts, and any housekeeping changes. Commit with a message that names the verdict and the close-out: +Stage `REPRODUCTION-SUMMARY.md`, the MyST report (`index.md`, `myst.yml`, any sub-analysis pages), `open-questions.md` (with resolutions), the updated CLAUDE.md, the final `astra.yaml`, the comparison artifacts, and any housekeeping changes. Commit with a message that names the verdict and the close-out: ``` review: verdict , summary at REPRODUCTION-SUMMARY.md @@ -93,7 +102,8 @@ This commit is the durable mark that the reproduction has reached close-out. Fut - `comparison-report.yaml` verdict is `pass` (or `partial` with un-acted opportunities logged) ⇒ ready to close out - `.lightcone/comparison.html` exists ⇒ `/figure-comparison` rendered - `open-questions.md` has a `## Resolutions` section covering every entry ⇒ open-questions walkthrough done -- `REPRODUCTION-SUMMARY.md` exists ⇒ final report written +- `REPRODUCTION-SUMMARY.md` exists ⇒ final summary written +- `index.md` drafted past the `lc init` TODO stub (or its skip logged as an Open opportunity) ⇒ MyST report authored - CLAUDE.md's *Open opportunities* list reflects the un-acted-on opportunities from the latest COMPARE ⇒ reconciliation done - A `review:` commit lands ⇒ REVIEW done; reproduction complete @@ -104,5 +114,5 @@ This commit is the durable mark that the reproduction has reached close-out. Fut - **The user owns the verdict-acceptance decision.** REVIEW's purpose is to let the user see what the loop's iterations did and decide whether they accept it. The skill renders surfaces and asks; it does not unilaterally close. - **Don't confuse with the per-phase reviews inside the loop.** ARCHITECT, SPECIFY, LITERATURE, and IMPLEMENT each have their own fresh-context review discipline that happens by iteration boundary. Those are unrelated to this close-out — same word, different jobs. The phase boundary makes them unambiguous: per-phase reviews live inside their host phase's reference; this one is the post-loop close-out in the user's main session. - **Open-question resolutions are durable.** Append to `open-questions.md`'s `## Resolutions` section so the next re-run / future session sees what was decided. Do not delete the original questions. -- **Keep the report short.** Long reports get skimmed; short reports get read. Two pages is generous. +- **Keep the summary short.** Long summaries get skimmed; short summaries get read. Two pages is generous. Depth belongs in the MyST report (Step 4), which telescopes into the spec rather than restating it. - **Do not invent further work.** If the user has accepted the verdict and the opportunities are propagated, the reproduction is done. The next session, the user, or a future revisit can decide whether tightening any open opportunity still serves them. diff --git a/claude/lightcone/skills/lc-new/SKILL.md b/claude/lightcone/skills/lc-new/SKILL.md index 4cac53cc..1ce42af1 100644 --- a/claude/lightcone/skills/lc-new/SKILL.md +++ b/claude/lightcone/skills/lc-new/SKILL.md @@ -146,6 +146,8 @@ Show summary table: Then tell the user the spec is ready and they can begin implementation. Recommend running `/clear` first — the scoping conversation consumes significant context, and everything needed to continue is captured in `astra.yaml` and `CLAUDE.md`. +Also mention the report: `lc init` scaffolded a template MyST report (`index.md` + `myst.yml`) that references the spec by path. `/lc-report` drafts it — the Introduction and Methods can be written as soon as the spec is stable; Results once `lc run` has materialized outputs. + --- ## Restrictions diff --git a/claude/lightcone/skills/lc-report/SKILL.md b/claude/lightcone/skills/lc-report/SKILL.md new file mode 100644 index 00000000..56ff7c41 --- /dev/null +++ b/claude/lightcone/skills/lc-report/SKILL.md @@ -0,0 +1,106 @@ +--- +name: lc-report +description: > + Authors and extends the project's MyST report — the external write-up + (`index.md` + `myst.yml`, scaffolded by `lc init`) that references + `astra.yaml` elements by tree-path through the MySTRA plugin instead + of restating them. Use whenever the user wants to write up an + analysis: "draft the report", "write up the results", "document the + analysis", "draft the introduction/methods/results", "turn this into + a paper", or when results have materialized and a write-up is the + natural next step. Also use to fix or extend an existing report page. + Not for per-element spec prose (`description:`/`rationale:` live in + `astra.yaml` — see /astra) and not for the HTML figure side-by-side + (/figure-comparison). +allowed-tools: Read, Write(*.md), Edit(*.md), Write(myst.yml), Edit(myst.yml), Glob, Grep, Bash(myst:*), Bash(astra:*), Bash(lc:*), AskUserQuestion +--- + +# /lc-report + +Author the project's report as MyST Markdown wired to the analysis through the MySTRA plugin. The plugin reads `astra.yaml` at build time and resolves `{astra}` references against it, so the report and the analysis cannot drift: figures, decisions, findings, and numbers stay single-sourced in the spec and in `results/`. + +Three layers, each with one source of truth — keep them separate: + +| Layer | Source of truth | +|---|---| +| **Data** — what a decision/output/finding *is* | `astra.yaml` + `universes/` + `results/` | +| **Composition** — what appears, where, in what order | the report pages (`index.md`, …) | +| **Presentation** — how it looks | the MyST theme | + +**The golden rule: never hard-type a measured number, restate a decision, or re-describe an output.** If it exists in `astra.yaml` or a result product, reference it by path. Every restated fact is a place the report can drift out of sync. + +Read [`references/mystra-syntax.md`](references/mystra-syntax.md) before drafting — it carries the exact path grammar, roles, directives, and options. Read [`references/craft.md`](references/craft.md) before writing prose. + +## Setup + +1. **Read the spec.** `astra.yaml` at the project root, plus each sub-analysis's `astra.yaml`. Note inputs, outputs, decisions, findings, prior insights, and the sub-analysis tree — these are the elements the report will reference. +2. **Note the active universe.** MySTRA resolves against the first `.yaml` file in `universes/` — it selects decision options and which `results//` artifacts resolve. +3. **Check materialization.** `lc status` — outputs that aren't materialized still embed (the spec entry renders) but `{astra:value}` reads from result files, so live numbers need `lc run` first. +4. **Check the report scaffold.** `lc init` writes `myst.yml` + `index.md` at the project root. If they're missing (e.g. a reproduction workdir that never ran `lc init`), create them — the minimal `myst.yml` is in [`references/mystra-syntax.md`](references/mystra-syntax.md). +5. **Check the MyST CLI.** `myst --version`. If absent, tell the user: `npm install -g mystmd` (or `uv tool install mystmd`). You can still draft without it, but you cannot validate. + +## Pick the mode + +Every mode drafts against the existing `astra.yaml`; what differs is the **second source** the prose draws on. If the mode isn't obvious from context, ask. + +| Mode | Second source | Guidance | +|---|---|---| +| **Paper reproduction** | An authoritative text (paper, thesis, report) at `work/reference/` | Read [`references/paper-reproduction.md`](references/paper-reproduction.md) — mapping table, fidelity rules, voice seams | +| **Co-drafting** | The user, in conversation | Ask before drafting: what's the research question, the current headline finding, what moved along the way, what would you claim today? Use provisional voice for in-flight work — hedge what's uncertain, claim what's settled, and mark volatile sections (e.g. *"(Provisional — revisit after `bao_fitting`.)"*) | +| **Retrofit** | Project artifacts — code, notebooks, commits, README | Harvest what the artifacts record; where a rationale isn't recoverable, say so explicitly (*"(Reconstructed 2026-07: original rationale not recorded.)"*) — never fabricate one | + +Hybrids are normal: a reproduction with co-drafted extensions, a retrofit with gaps the user fills in conversation. + +## Structure the report + +Sections mirror the analysis, not a template. The default single-page shape: + +- **Introduction** — the research question, its context, why it matters. Cite prior insights with `{astra:cite}` where the literature motivates the work. +- **Methods** — walk the pipeline in DAG order. Reference each decision where it shapes the pipeline and embed the load-bearing ones as blocks; the option tabs and rationale render from the spec. +- **Results** — embed the output figures/tables/metrics as blocks; pull measured numbers into prose with `{astra:value}`; embed or reference findings where the results support claims. +- **Discussion / Conclusions** — synthesis; findings referenced inline, implications in your own prose. + +**Multi-page when the analysis has sub-analyses.** One page per sub-analysis, named by dotted filename (`reconstruction.md`, `reconstruction.features.md`), listed in `myst.yml`'s `toc:`. The root page is the end-to-end view — it traces raw inputs to final outputs and embeds each sub-analysis's nav card (`:::{astra} reconstruction` `:::`); details telescope into the sub-analysis pages. A reader lands cold on `index.md` and gets the shape of the whole work. + +## Draft order + +Not introduction-first — the opening compresses the rest, so write it last. + +1. **Methods** — the pipeline walk. Weave decision references into the argument; don't recite them as a list. Too many decisions to weave coherently means the report wants a sub-analysis page, not a longer paragraph. +2. **Results** — one block embed per promoted output, numbers in prose via `{astra:value}`, findings woven in where the evidence lands. +3. **Discussion** — how the findings relate; what they mean. +4. **Introduction** (and abstract, if wanted) — last. Open with the question and the headline finding; no field primer. + +**Coverage:** every declared finding, load-bearing decision, and promoted output should be referenced somewhere in the report. An element genuinely not worth a mention is a hint it shouldn't be declared — surface that to the user rather than padding prose around it. + +## Validate — build, fix, repeat + +MySTRA verifies references against `astra.yaml` and `results/` at build time. After drafting (and after any spec change), run: + +```bash +myst build --html +``` + +Then fix everything it surfaces, and build again until clean: + +- `[mystra]` warnings in the build output (unknown ids, invalid `when:` refs, scope problems). +- Error admonitions in the rendered page — a directive path that didn't resolve renders an error box naming the path and reason. +- Inline error tokens from broken `{astra:value}` — e.g. `⟨value: no column "alpha2" in "bao_table"⟩` for a missing result file, unknown column, or filter matching no row. + +Broken references never crash the build — they render visibly. Never leave one in a finished report. For interactive review, offer the user `myst start` (live preview at `localhost:3000`; note it only watches `.md` files — after editing `astra.yaml`, re-save a page to re-render). + +## Restrictions + +- **Only touch report pages and `myst.yml`.** Spec changes go through the normal `astra.yaml` discipline (see /astra), not through this skill. Never edit anything under `results/`. +- **Never hard-type a value that a `{astra:value}` reference can pull.** If a number isn't reachable (not a declared output), that's a spec gap to surface, not a license to type it. +- **Paraphrase, don't lift.** In reproduction mode, restate the source's claims in your own structure; preserve its confidence register (don't sharpen "we detect" into "we strongly detect", don't soften a hedge). + +## Anti-patterns + +- **Hard-typed numbers.** "α = 0.0696" typed in prose goes stale the first time the pipeline reruns. Use `{astra:value}`. +- **Restating instead of embedding.** Three paragraphs describing what a decision's options are duplicates the spec; embed the decision and let the prose say why it matters. +- **Registry dumping.** `:::{astra} outputs` on every page is an inventory, not a report. Registries are for appendices and navigation; the body places individual elements where the argument needs them. +- **Wiki-style primer.** "BAO is the baryon acoustic oscillation feature…" — readers arrive with context. Open with the load-bearing statement and a reference. +- **Decision-list paragraph.** "We made the following decisions: A, B, C." Reference each decision where it shapes the pipeline. +- **Skipping the build loop.** A report that was never built can hide broken paths behind plausible-looking syntax. Build before declaring done. +- **Stale filters.** A `{astra:value}` `where=` filter written against an old table layout renders an error token — fix the filter, don't paper over it with a typed number. diff --git a/claude/lightcone/skills/lc-report/references/craft.md b/claude/lightcone/skills/lc-report/references/craft.md new file mode 100644 index 00000000..43c4d71c --- /dev/null +++ b/claude/lightcone/skills/lc-report/references/craft.md @@ -0,0 +1,49 @@ +# Report craft + +Prose discipline for the report. The report does not duplicate the analysis — it cites into it. A reference is a citation; a sentence pointing at a decision is a small argument; the report is the layer where decisions, sub-analyses, findings, and outputs become a connected story. + +## References carry the argument + +- **Reference text is authored prose, not a raw id.** `{astra}`the post-reconstruction catalogs `` reads as a sentence; `{astra}`reconstruction`` alone reads as a label. Use the `text ` form whenever the bare label wouldn't sit naturally in the sentence. +- **Inline references do the work of a citation.** Don't footnote or parenthesize what an inline reference can carry. +- **One reference per idea.** Three references stacked on a sentence means the sentence carries too much; split it or drop one. +- **Decision vs. selection.** `{astra}`decisions.algorithm`` names the *decision*; `{astra:value}`decisions.algorithm`` names the *option active under the universe*. Whenever the sentence depends on which option is active ("we reconstruct with **MultiGrid**"), use the value form so the prose updates with the universe. + +## Make the data flow navigable + +References are the trail a reader follows through the pipeline without leaving the prose. + +- When Results discusses a sub-analysis's output, name its downstream consumers by reference: *"the reconstructed field feeds {astra}`the post-reconstruction BAO fit ` and supports {astra}`the headline detection `."* +- The root page (`index.md`) is the end-to-end view: it traces raw inputs → sub-analyses → final outputs in a few sentences, with each stage referenced or embedded as a nav card. Details telescope into the sub-analysis pages. + +## Length + +1–3 paragraphs per section topic, at any level (root page, sub-analysis page). Length discipline is what keeps analyses modular, not a style preference: if the references don't fit in three paragraphs, the analysis is too big for one section — split it into a sub-analysis page. The report is a compressor; if it won't compress, split the thing being compressed. + +## Sentence craft + +- **Economy.** Every sentence introduces a new idea or sharpens one. Release real verbs: `conducted cross-correlation` → `cross-correlated`. +- **Specificity.** Names, references, and `{astra:value}` numbers over generic claims. +- **Arrive through content.** No "in this report we will describe…"; the content is the opening. + +### Real subjects, real verbs + +"We measure the BAO peak with the LRG sample" reads as agency. "The measurements of the BAO peak reveal a 7σ detection" reads as zombie-noun abstraction. The test: can you picture someone or something physically doing the verb? If not, rewrite. + +Valid subjects: + +- **We** — for decisions and actions ("we chose the Gaussian damping prior") +- **The thing itself** — for states and properties ("the covariance is dominated by shot noise") +- **Passive voice** — when the actor is obvious ("a redshift cut is applied") +- **Results / data as epistemic subjects** — for what the data shows ("the measurement shows a 7σ peak"; "Figure 2 reveals…") +- **Physics doing physics** — for physical processes ("lensing distorts shapes"; "higher-order effects produce B-modes") + +Anthropomorphized abstractions fail the test: "the methodology validates," "this analysis demonstrates," "the catalogue evolution follows." Rewrite to a real subject doing a real verb. + +## Anti-patterns + +- **Wiki-style what-is framing.** "BAO is the baryon acoustic oscillation feature." A wiki summarizes; a report points into reasoning. Replace with the load-bearing statement and a reference: "we chose {astra}`the Gaussian damping prior ` over flat because flat admitted spurious minima." +- **Decision-list paragraph.** "We made the following decisions: A, B, C." Reference each decision where it shapes the pipeline, not as recitation. Too many to weave coherently → the report wants a sub-analysis page. +- **Introduction as primer.** Teaching what the field is. Readers arrive with context; open with the question and the headline finding. +- **Describing what an embed already shows.** A paragraph enumerating a decision's options above `:::{astra} decisions.algorithm` `:::` duplicates the tabs the embed renders. The prose says why the decision matters; the embed says what it is. +- **Uncited declared elements.** Every declared finding, load-bearing decision, and promoted output belongs somewhere in the report. If an element genuinely isn't worth a mention, question whether it should be declared — surface that, don't pad. diff --git a/claude/lightcone/skills/lc-report/references/mystra-syntax.md b/claude/lightcone/skills/lc-report/references/mystra-syntax.md new file mode 100644 index 00000000..192b4c9d --- /dev/null +++ b/claude/lightcone/skills/lc-report/references/mystra-syntax.md @@ -0,0 +1,210 @@ +# MySTRA syntax reference + +MySTRA is a MyST plugin (a single `.mjs` loaded by URL in `myst.yml` — nothing to install) that resolves `{astra}` references against `astra.yaml` at build time. Everything else is ordinary MyST — prose, math, citations, numbering, multi-page structure all come from the stock `myst` engine. Full upstream docs: . + +## Choosing a surface + +| You want to… | Use | +|---|---| +| Mention an element in a sentence | `{astra}` role | +| Refer to a placed figure by number ("Figure 3") | `{astra:ref}` | +| Cite the literature behind an insight | `{astra:cite}` / `{astra:cite:t}` | +| Put a measured number in prose | `{astra:value}` | +| Embed a figure/decision/finding as a block | `{astra}` directive | +| Link to a placed block with custom text | `[text](#-)` anchor | +| Split the report along sub-analyses | multi-page (dotted filenames) | + +## Path grammar + +Paths are dot-separated routes through the analysis tree, mirroring `astra.yaml` (the same spelling as `when: decision.option` and recipe `{inputs.id}` placeholders). Paths always resolve from the **root analysis**, on every page. + +``` +outputs.hubble_diagram an output (figure / table / metric / …) +decisions.algorithm a decision +decisions.algorithm.gp one option of a decision +findings.sig.fig1 one evidence record of a finding +prior_insights.recon_sharpens_bao a prior insight +inputs.raw_catalog an input +reconstruction.outputs.xi an output in the `reconstruction` sub-analysis +reconstruction the sub-analysis itself +outputs a whole collection (a registry) +``` + +- Collections are exactly the `astra.yaml` keys: `inputs`, `outputs`, `decisions`, `findings`, `prior_insights` (alias `prior-insights`), `analyses`, `universes`. +- Sub-analysis ids may be written directly — the `analyses.` prefix is implied — and nest to any depth: `clustering.correlation.outputs.xi`. +- Child long forms exist too: `decisions..options.`, `findings..evidence.`. +- A path stopping at a collection addresses the whole collection: `outputs`, `reconstruction.inputs`. +- Final segments are the `id`s from the spec; MySTRA renders the element's `label:` (or `name:` for analyses), falling back to the id with underscores → spaces. + +## Inline mention — the `{astra}` role + +```markdown +We adopt the {astra}`decisions.algorithm` and report {astra}`outputs.hubble_diagram`, +which confirms {astra}`findings.signal_detected`. +``` + +Custom display text uses MyST's `text ` convention: + +```markdown +{astra}`our preferred method ` +``` + +Any path works: decisions, options, outputs, findings, prior insights, inputs, sub-analyses, elements inside sub-analyses. + +## Numbered reference — `{astra:ref}` (alias `{astra:numref}`) + +A native numbered cross-reference ("Figure 3") to an output **placed as a block somewhere in the report** — sugar for `[Fig. %s](#output-)`. If the target is never embedded, there is nothing to point at. + +```markdown +{astra:ref}`outputs.hubble_diagram` # "Figure 3" +{astra:ref}`see Fig. %s ` # custom text; %s is the number +``` + +## Citations — `{astra:cite}` and `{astra:cite:t}` + +Turns DOI-backed evidence on findings/prior insights into real bibliographic citations through MyST's citation pipeline. Findings and prior-insight paths only. + +```markdown +{astra:cite}`prior_insights.recon_sharpens_bao` # "(Chen et al., 2024)" — parenthetical +{astra:cite:t}`prior_insights.recon_sharpens_bao` # "Chen et al. (2024)" — textual +``` + +Every distinct DOI on the element's evidence is cited (multiple DOIs render as a group). An element with no DOI evidence falls back to a plain inline reference. + +## Live values — `{astra:value}` + +Interpolates a real number from the resolved analysis at build time. The role body is the path; selection is expressed as inline options inside the braces: + +```markdown +{astra:value col=DV_over_rd where="tracer=lrg3_elg1" pm=true}`outputs.bao_distance_table` → 19.88 ± 0.17 +{astra:value col=alpha1 where="tracer=elg1 recon=Pre" sig=3}`outputs.bao_alpha_values` → 0.0696 +{astra:value}`outputs.chi2_reduced` → 1.5 +{astra:value}`decisions.algorithm` → MultiGrid +``` + +| Option | Meaning | +|---|---| +| `col=` | Column to read (required for table outputs). | +| `where="k=v …"` | Row filters; space- or comma-separated `key=value` pairs, all must match (case-insensitive). Must select exactly one row. Alias: `filter=`. | +| `pm=true` | Also render uncertainty: `_std` for tables, the metric's own uncertainty for metrics. | +| `err=` | Explicit uncertainty column (instead of the `_std` convention). | +| `sig=` | Significant figures (default 4; uncertainties render with 2). | + +- Quote values containing spaces (`where="tracer=lrg3 recon=Post"`); bare is fine otherwise (`col=alpha`). +- **Table outputs** read the materialized CSV/JSON. **Metric outputs** (a JSON scalar, `[value, uncertainty]`, or `{value, uncertainty, unit}`) interpolate directly, no options needed. +- **Decisions:** `{astra:value}`decisions.`` renders the label of the **option selected under the active universe** — use it whenever prose depends on which option is active, so the sentence updates with the universe. (`{astra}`decisions.`` names the decision itself.) +- Inline role options are recent mystmd; if `myst` reports an unknown role for `{astra:value col=…}`, update the CLI. + +## Block embeds — the `{astra}` directive + +```markdown +:::{astra} outputs.bao_fit_plot +:caption: The post-reconstruction fit; see {astra}`decisions.algorithm`. +:label: fig-bao +::: +``` + +What each path renders: + +| Path | Renders | +|---|---| +| `outputs.` | The real figure / table / metric, with provenance | +| `decisions.` | Label, rationale, options as tabs, the universe's selection marked | +| `decisions..