diff --git a/skills/how-to-write-ideas-report/SKILL.md b/skills/how-to-write-ideas-report/SKILL.md index cd2af35..2753f26 100644 --- a/skills/how-to-write-ideas-report/SKILL.md +++ b/skills/how-to-write-ideas-report/SKILL.md @@ -26,7 +26,7 @@ Write a structured ideas report after a `brainstorm-ideas` session has converged Follow `skills/how-to-technical-writing/SKILL.md` for sentence- and paragraph-level prose rules. Follow `skills/how-to-write-ideas-report/references/writing-workflow.md` for context loading, citation handling, gap-filling research, output format, diagrams, and finish checks. - Primary source: `docs/discussion/*-brainstorm-ideas-log.md`. If multiple logs exist and the request does not identify one, ask which to use. -- If no log exists, ask the user to brainstorm first or describe the chosen direction and reasoning to preserve. +- If no log exists, use the chosen direction and reasoning already in the conversation or supplied notes. Ask only for substance needed to write the requested report. - Save to `articles/YYYY-MM-DD--ideas-report.{md,typ,tex}` with a matching bibliography when citations are used. - When entering from `brainstorm-ideas` Phase 3, carry forward the active conversation log, user profile, chosen direction, key references, and concrete action plan without asking the user to repeat them. diff --git a/skills/how-to-write-ideas-report/references/writing-workflow.md b/skills/how-to-write-ideas-report/references/writing-workflow.md index 1d092c9..8cd409d 100644 --- a/skills/how-to-write-ideas-report/references/writing-workflow.md +++ b/skills/how-to-write-ideas-report/references/writing-workflow.md @@ -6,11 +6,15 @@ Resolve the installed `how-to-download-ref` skill from the agent's catalog and s ## Context -- Resolve the project KB with `KB=$(python3 "$DOWNLOAD_REF_DIR/helpers/resolve_kb.py")`. -- If present, read `$KB/NOTES.md`, `$KB/INDEX.md`, and the canonical bib `$KB/references.bib`. +Start from what the user supplied: text, source files, scope, format, and any +authorization already given. A local prose edit needs the passage plus the +definitions and citations it depends on, not the whole KB or conversation history. + +- Resolve the project KB when KB-backed context is needed: `KB=$(python3 "$DOWNLOAD_REF_DIR/helpers/resolve_kb.py")`. +- Read `$KB/INDEX.md` and `$KB/NOTES.md` for the topic, then the relevant notes and bibliography entries. Screening the whole bibliography belongs to an explicitly selected review. - Read `docs/discussion/user-profile.md` when audience, background, or positioning matters. -- For ideas/manuscripts, read relevant `docs/discussion/*-brainstorm-ideas-log.md`. -- If the needed literature base is missing, suggest the `survey` skill or ask the user for explicit source files. +- For ideas/manuscripts, read the relevant `docs/discussion/*-brainstorm-ideas-log.md`, starting from the wrap-up section. +- Papers the user supplied and a manuscript-local bibliography are valid sources without a sci-brain KB. If the needed literature base is missing, suggest the `survey` skill or ask the user for explicit source files. The canonical bib is `$KB/references.bib`. @@ -18,13 +22,13 @@ The canonical bib is `$KB/references.bib`. ## Scope the source set -A write-up covers a *subset* of the bib — the references the relevant `NOTES.md` section(s) actually cite, not all 100+ accumulated entries. Determine that subset deterministically instead of by eye: +For a KB-backed report, a write-up covers a *subset* of the bib — the references the relevant `NOTES.md` section(s) actually cite, not all 100+ accumulated entries. Determine that subset deterministically instead of by eye: ```sh python3 "$DOWNLOAD_REF_DIR/helpers/scope_refs.py" --notes "$KB/NOTES.md" --bib "$KB/references.bib" ``` -It prints the scoped cite keys (one per line) and exits non-zero if any `[@key]` anchor in the notes has no bib entry — fix dangling anchors before drafting. Use `--json` for `{scoped, missing, unused}`. Draft against the scoped keys; the `unused` list is out of scope unless the user asks to widen it. +When the user supplied explicit sources instead, use those directly; do not require NOTES.md. The helper prints the scoped cite keys (one per line) and exits non-zero if any `[@key]` anchor in the notes has no bib entry — fix dangling anchors before drafting. Use `--json` for `{scoped, missing, unused}`. Draft against the scoped keys; the `unused` list is out of scope unless the user asks to widen it. ## References @@ -61,11 +65,16 @@ For Typst, prefer native `grid` + `rect` + fixed-width `box()` for text-heavy la Run these checks before declaring the document done — do not eyeball them: -- **Compile** the document (`typst compile .typ`, or the LaTeX/Markdown equivalent) and confirm it exits cleanly. -- **No dangling citations.** Grep the compile log for unresolved-reference warnings; for Typst, a missing key warns rather than errors, so an empty grep is the pass condition: +- **Compile** the document and check both the exit status and the log. For Typst, a missing cite key only warns, so a clean exit alone is not a pass; the block below fails on a nonzero exit *or* on any warning, and prints the log either way (replace `main.typ` with the source file): ```sh - typst compile .typ 2>&1 | grep -i "unresolved\|warning" || echo "clean" + LOG=$(mktemp) + typst compile main.typ >"$LOG" 2>&1; status=$? + cat "$LOG" + grep -Eiq 'unresolved|warning' "$LOG" && status=1 + rm -f "$LOG" + [ "$status" -eq 0 ] && echo clean ``` + Use the LaTeX/Markdown equivalent for other formats. Read every warning before calling the build clean. - **Every scoped claim is cited.** Confirm each `@key` in the prose resolves to a bib entry and that no scoped key was silently dropped (cross-check against `scope_refs.py` output). - **Non-empty bibliography** renders in the output. - Report the output path and any skipped verification. diff --git a/tests/test_writing_workflow.py b/tests/test_writing_workflow.py new file mode 100644 index 0000000..62a5c07 --- /dev/null +++ b/tests/test_writing_workflow.py @@ -0,0 +1,57 @@ +"""Execute the documented Typst build check against realistic outcomes.""" + +import os +import re +import subprocess +from pathlib import Path + +import pytest + + +ROOT = Path(__file__).resolve().parents[1] + + +@pytest.mark.parametrize( + "compiler_exit,diagnostic,expected_exit", + [ + (0, "", 0), + (0, "warning: unresolved citation", 1), + (2, "error: unknown variable", 1), + (127, "compiler unavailable", 1), + ], +) +def test_documented_compile_check_handles_failure_and_warnings( + tmp_path, compiler_exit, diagnostic, expected_exit +): + workflow = ( + ROOT / "skills/how-to-write-ideas-report/references/writing-workflow.md" + ).read_text() + blocks = re.findall(r"```sh\n(.*?)\n\s*```", workflow, re.DOTALL) + checks = [block for block in blocks if "typst compile" in block] + assert len(checks) == 1 + + compiler = tmp_path / "typst" + compiler.write_text( + '#!/bin/sh\nprintf "%s\\n" "$TEST_DIAGNOSTIC" >&2\n' + 'exit "$TEST_COMPILER_EXIT"\n' + ) + compiler.chmod(0o755) + logs = tmp_path / "logs" + logs.mkdir() + env = { + **os.environ, + "PATH": str(tmp_path) + os.pathsep + os.environ["PATH"], + "TMPDIR": str(logs), + "TEST_DIAGNOSTIC": diagnostic, + "TEST_COMPILER_EXIT": str(compiler_exit), + } + result = subprocess.run( + ["/bin/sh", "-c", checks[0]], + cwd=tmp_path, + env=env, + capture_output=True, + text=True, + ) + assert result.returncode == expected_exit, result + assert diagnostic in result.stdout + result.stderr + assert not list(logs.iterdir()), "temporary compiler log was not removed"