Commit b301295
Phase 1: fast inner loop + telemetry foundations (#717)
* feat(pipeline): Phase 1 — fast inner loop + telemetry foundations
Inner loop (all measured on this machine, GHC 9.8.4, -O0 dev flavor):
- cabal.project.dev: committed dev build flavor (optimization: 0)
- scripts/dev-loop: persistent ghcid typecheck loop writing
.ghcid-errors.txt — measured 0.55s error feedback, 1.9s recovery
(target <5s). Resolves ghcid via PATH or nix shell nixpkgs#ghcid.
- scripts/test-match: link-free hspec --match inside cabal repl —
measured 9.2s (target <30s); parses the hspec summary for a real
exit code since ghci always exits 0.
- scripts/refresh-dev-cache: warm-cache refresh + modules-rebuilt
cache-health metric for pool worktrees.
- session-start hook: best-effort background docker compose up -d
(warm Postgres for the gated suites), local + remote.
Telemetry (schema v1 frozen in telemetry/SCHEMA.md):
- scripts/telemetry.py: one validated JSON line per pipeline run to
telemetry/runs.jsonl; closed failure-label taxonomy ('other'
requires a note); golden-task archiver (telemetry/golden/,
gitignored for now). Dogfood run 2026-07-07-001 recorded.
Profiling findings recorded in SCHEMA.md: full nhcore -O0 = 249
modules/54s; recompilation is content-hash based; leaf edit = 4.9s;
interface-preserving edits don't cascade.
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(pipeline): Phase 1 follow-up — ghcid in dev shell, human-tool parity doctrine
- nix/hix.nix: add ghcid to shell.tools (verified locally: resolves from
cache.iog.io, no source build — the CI shell rebuild is a cache hit).
- README: new "Fast inner loop" section — the pipeline scripts are the
human dev commands, deliberately the same scripts; plus an honest
warning on the Linting section (hlint config doesn't encode the
dialect and doesn't run in CI until Phase 2).
- Plan: second governing rule — "Every pipeline tool is a human tool":
same script/environment/flavor for agents and humans, non-interactive
by default, telemetry from pipeline runs only, human-runnable as an
acceptance criterion for every pipeline asset.
- AGENTS.md: parity + telemetry-discipline notes.
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(pipeline): address CodeRabbit review — panel-verified, all 5 findings valid
- scripts/test-match: reject vacuous success — "0 examples, 0 failures"
(typo'd pattern / wrong suite) now exits 1 with a distinct "no specs
matched" message instead of reporting a pass for tests that never ran.
A verification oracle must never return vacuous success. (Major)
- scripts/telemetry.py: enforce the closed failure-label taxonomy on
EVERY finish call, not only failed/parked; stricter than suggested —
'ok' runs must not carry a failure label at all. (Major)
- scripts/telemetry.py: validate run_id against
^[A-Za-z0-9][A-Za-z0-9._-]*$ at start and before golden archiving
(guards the telemetry/golden/<run_id>/ path); format documented in
SCHEMA.md as the de-facto run-id contract. (flagged Critical;
panel notes severity inflated for a single-operator tool — fixed anyway)
- scripts/telemetry.py: reject negative --seconds/--repair-rounds/--count. (Minor)
- AGENTS.md: un-glue "[suite]#" in the shell example. (Minor)
All rejection paths exercised: 6 telemetry guards + vacuous/real
test-match runs; runs.jsonl untouched by the validation tests.
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(pipeline): scripts self-provision the toolchain via with-toolchain
Loop scripts no longer assume they run inside the flake dev shell —
an agent (or human) can invoke them from any bare shell:
- scripts/with-toolchain: runs a command with the pinned toolchain.
Fast path only when IN_NIX_SHELL is set AND the command actually
exists (an inherited shell can be STALE — e.g. predate ghcid's
addition to the flake; discovered live when exactly that happened);
otherwise wraps in `nix develop --command` (~0.4s warm); loud
host-tools fallback when nix is absent.
- dev-loop / test-match / refresh-dev-cache route every tool call
through it; dev-loop's ad-hoc `nix shell nixpkgs#ghcid` fallback
removed (ghcid now comes from the flake shell).
- SCRIPT_DIR captured before cd (relative invocation from subdirs
was broken).
- Docs: SCHEMA.md wrapper overhead + config-hash caveat (first ghcid
load re-interprets all modules if dist-newstyle was built under a
different env); AGENTS.md + README notes.
Verified: wrapped dev-loop full load (249 modules, "All good"),
test-match pass through wrapper (3.9s), refresh-dev-cache
(0 modules rebuilt), wrapper overhead 0.4s warm.
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(pipeline): ./dev — single entrypoint for the shared human/agent dev tools
Panel-reviewed dispatcher (zero-dependency bash, deliberately not a task
runner): ./dev with no args lists the menu; implementations stay in scripts/.
- Verbs describe intent, not mechanism: watch / check / test / refresh / exec.
- dev-loop's conflation split: `watch` = resident ghcid daemon (plumbing,
once per session); `check` = the instantaneous typecheck status agents
and humans actually call (reads the watcher file; one-shot -O0
typecheck fallback when no watcher runs).
- telemetry.py deliberately NOT on the menu — emission is pipeline-only
by doctrine; a discoverable verb would invite ad-hoc pollution.
- Standing rule added to the entrypoint header: every future pipeline
asset registers a verb here or it doesn't ship (operationalizes the
human-runnable acceptance criterion).
- README / AGENTS.md / SCHEMA.md updated to the verb interface.
Verified: usage listing, check fallback (exit 0), test (exit 0),
exec (ghc resolves), unknown verb (exit 2).
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(pipeline): ./dev doctor — mechanical enforcement of verb registration
A rule without a check is a wish (this repo's founding lesson). The
"every pipeline asset registers a ./dev verb" rule now has its gate:
- scripts/doctor: enumerable domain (asset := file in scripts/) +
bidirectional set check — every registered verb resolves to an
existing executable script (no dangling menu entries, no missing +x),
every script has a verb OR a reasoned exemption, and no stale
exemptions (exempt+registered = contradiction). Exemptions live in
one reviewable array with reasons (telemetry.py: pipeline-only
doctrine; cloud-setup.sh: platform-invoked; install.sh: end-user).
- .github/workflows/checks.yml: fast governance job (pure bash, no
nix, seconds) running ./dev doctor on every PR — Phase 2's hlint
gate joins this workflow later.
- Legacy scripts triaged into verbs: ./dev doctest, ./dev test-all.
- Plan: third governing rule — "every governing rule names its gate" —
with the current rule→gate pairings recorded.
Verified: pass case (8 verbs, 11 scripts, 3 exemptions), adversarial
unregistered-script case fails with actionable message.
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(pipeline): address bot review round 2 — workflow hardening + input edges
CodeQL/GitHub Advanced Security + CodeRabbit findings, all valid:
- checks.yml: permissions: contents: read (closes the CodeQL alert),
concurrency group with cancel-in-progress, checkout pinned to the
v4.2.2 SHA with persist-credentials: false.
- scripts/watch: TARGET is spliced into ghcid's shell-evaluated
--command string (unlike sibling scripts where targets travel as
argv) — now restricted to cabal target charset; metacharacters
exit 2 before any shell sees them.
- scripts/test-match: escape backslashes/quotes in PATTERN before it
lands inside ghci's :main string literal — embedded quotes silently
garbled the match, the exact vacuous-result bug this script guards
against.
- scripts/check: accepts [target] like its siblings; the one-shot
fallback no longer hardcodes lib:nhcore.
Verified live: injection attempt rejected (exit 2), quoted pattern
survives escaping and reports vacuous match honestly (exit 1),
./dev doctor green.
Part of #715 (Phase 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: NickSeagullBot <bot@nickseagull.dev>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent 050c84e commit b301295
18 files changed
Lines changed: 688 additions & 2 deletions
File tree
- .claude/hooks
- .github/workflows
- docs/plans
- nix
- scripts
- telemetry
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
25 | 33 | | |
26 | 34 | | |
27 | 35 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
37 | 55 | | |
38 | 56 | | |
39 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
83 | 107 | | |
84 | 108 | | |
85 | 109 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
Lines changed: 5 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
0 commit comments