You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cold handoff of the fold / TypeScript-as-Data workstream. Read this end to end before doing anything. It encodes decisions already made, traps already hit, and the verification discipline that this work has repeatedly proven necessary.
Your role: orchestrator, not implementer
You dispatch subagents, interrogate them, verify their claims independently, and merge. You do not implement the features yourself. The exceptions are small, surgical fixes (a one-line cast, a doc line) and — always — measurement, which you do yourself and never delegate.
The reason is not efficiency. Every serious defect in this workstream was caught by the orchestrator re-measuring, not by the implementing agent. Two agents shipped confident, well-written reports that were wrong on their central claim. So did the previous orchestrator, three times. Verification is the job.
Model selection
Sonnet by default. Every feature agent in this workstream ran on Sonnet and the engineering quality was consistently good — including one that correctly defended its result against a wrong orchestrator claim.
Opus when there is risk. Use it for: anything touching the fold subset or the sandbox boundary, security-relevant work, ambiguous root-cause hunts, and any task where a wrong answer would be expensive to detect. The intermittent-hang investigation is the archetype — it burned three agents and hours of wall clock because the failure was nondeterministic and every plausible theory was wrong.
Signal to escalate: the task requires falsifying a hypothesis rather than building to a spec.
Interrogate your agents
Do not accept a completion report at face value, and do not wait passively for one.
Mid-flight, ask: what is your current hypothesis, what have you measured, what have you ruled out and how? Ask for measurements, not reasoning. Explicitly tell them "still characterizing" is an acceptable answer — that permission is what stops an agent inventing a confident theory to fill silence.
Before dispatch, make them restate the acceptance criterion in their own words if the task is subtle. Two agents optimized a proxy metric because the real goal was one layer removed from what the issue said.
When a report contains a claim that shifts blame to pre-existing code, treat that as a flag. It happened twice; both times the claim was wrong and one cheap experiment falsified it. Ask for that experiment.
When an agent pushes back on you, take it seriously. One correctly corrected a stale baseline. Being challenged by a subagent is a signal to re-check your own numbers, not to reassert.
The goal
Fold becomes the default path for real chant applications, so that describing chant as statically folding TypeScript is simply true rather than aspirational.
Coverage percentage on the example corpus is a proxy and a weak one — the corpus is chant's own curated code, is expected to shrink, and can be moved by editing examples. That is metric-gaming; do not do it.
The real metric is loomster (/Users/alex/checkouts/intentius/loomster), a full application built on chant. Currently 13 of 55 files fold. The warden repos are secondary targets. Any decision about making fold default-on should be measured there.
Measurement traps — all five were hit, do not repeat them
Never symlink node_modules between checkouts. It resolves lexicon plugins to the wrong tree and produces confidently wrong numbers. This cost a full review cycle and a false accusation against a correct PR.
Never capture parallel output to one file.xargs -P 6 … > out.txt interleaves six builds and destroys entry boundaries. Write one file per entry. This produced a fabricated "16 file regressions" that did not exist.
Verify a mutation applied before trusting the result. Three separate "the guard did not fire" conclusions came from perl/sed patterns that silently did not match. Always diff and confirm before running.
One passing run proves nothing for anything intermittent. The hang reached CI because local runs passed. Require 5+ consecutive clean runs.
Never run two full suites concurrently and then interpret a timeout. Contention looks exactly like a hang.
Two message wordings exist for the same fold rejection (function call as a value and call expression as a value), and reasons embed the entire multi-line source node — so line-based grepping of fold output silently miscounts. Parse whole blocks. Tracked as #1054.
Operational safety
This machine hard-crashed early in this work: a runaway test run exhausted 64GB, the kernel jettisoned ~300 daemons, and it cost a reboot. Since then:
Cap every run. A single test file past ~3 minutes is a bug, not slowness. Full suite baseline is ~45s local, ~7m CI.
A repeat-until-hang harness with process/CPU/fd diagnostics lives at scratchpad/hang-hunt2.sh in the session scratch dir — reuse the pattern.
vitest.config.ts now caps per-fork heap derived from host memory and core count, so a runaway fails as a test rather than killing the machine. Do not remove it.
feat(core): fold registered plain-call intrinsics (per-intrinsic opt-in) — DECIDED: yes #1044 / subset.ts — give the shared subset an optional intrinsic registry (exact with one, conservatively rejecting without). Decided on outcomes: subset.ts documents that it may only ever be permissive relative to fold(), never stricter, and keeping the call case out of it would make it systematically stricter. It is also the only choice that keeps the predicate usable by downstream tooling like behold, which needs to ask "will this fold?" without running fold.
Examples may be rewritten or dropped, but only after capability work lands — most current example blockers are about to become foldable, so rewriting first is wasted effort.
In flight: PR #1081 (#1064, build-time parameters). CI pending at handoff. The agent self-caught a performance regression it introduced — reintroducing the cold bare-specifier resolution cost that #1020 had eliminated — and fixed it in c4707dd5. Verify with the repeat-run harness before merging; this exact regression class has bitten twice.
Loomster PR #156 and issue #155 exist for the params migration. Do not merge #156 until a chant release containing #1064 is published — its CI installs chant from npm and will fail otherwise. Releases are cut by pushing a chant-v* tag, which triggers .github/workflows/publish.yml. Current version 0.19.1. Publishing is irreversible and outward-facing: surface that decision to the maintainer rather than tagging unilaterally.
Also open from the lexicon-contract sweep: #1068, #1070, #1071, #1072 — pre-existing per-lexicon debt, now visible and gated via KNOWN_FAILURES in scripts/check-lexicons.ts.
What "done" looks like
Not a corpus percentage. Loomster folding a large majority of its files, with the remainder being patterns that should never fold — process.env reads, arrow functions, user helper functions. At that point the question of making fold default-on becomes answerable on evidence, and the positioning becomes true.
Cold handoff of the fold / TypeScript-as-Data workstream. Read this end to end before doing anything. It encodes decisions already made, traps already hit, and the verification discipline that this work has repeatedly proven necessary.
Your role: orchestrator, not implementer
You dispatch subagents, interrogate them, verify their claims independently, and merge. You do not implement the features yourself. The exceptions are small, surgical fixes (a one-line cast, a doc line) and — always — measurement, which you do yourself and never delegate.
The reason is not efficiency. Every serious defect in this workstream was caught by the orchestrator re-measuring, not by the implementing agent. Two agents shipped confident, well-written reports that were wrong on their central claim. So did the previous orchestrator, three times. Verification is the job.
Model selection
Interrogate your agents
Do not accept a completion report at face value, and do not wait passively for one.
The goal
Fold becomes the default path for real chant applications, so that describing chant as statically folding TypeScript is simply true rather than aspirational.
Coverage percentage on the example corpus is a proxy and a weak one — the corpus is chant's own curated code, is expected to shrink, and can be moved by editing examples. That is metric-gaming; do not do it.
The real metric is loomster (
/Users/alex/checkouts/intentius/loomster), a full application built on chant. Currently 13 of 55 files fold. The warden repos are secondary targets. Any decision about making fold default-on should be measured there.Measurement traps — all five were hit, do not repeat them
node_modulesbetween checkouts. It resolves lexicon plugins to the wrong tree and produces confidently wrong numbers. This cost a full review cycle and a false accusation against a correct PR.xargs -P 6 … > out.txtinterleaves six builds and destroys entry boundaries. Write one file per entry. This produced a fabricated "16 file regressions" that did not exist.perl/sedpatterns that silently did not match. Alwaysdiffand confirm before running.Two message wordings exist for the same fold rejection (
function call as a valueandcall expression as a value), and reasons embed the entire multi-line source node — so line-based grepping of fold output silently miscounts. Parse whole blocks. Tracked as #1054.Operational safety
This machine hard-crashed early in this work: a runaway test run exhausted 64GB, the kernel jettisoned ~300 daemons, and it cost a reboot. Since then:
scratchpad/hang-hunt2.shin the session scratch dir — reuse the pattern.vitest.config.tsnow caps per-fork heap derived from host memory and core count, so a runaway fails as a test rather than killing the machine. Do not remove it.Decisions already made — do not relitigate
subset.ts— give the shared subset an optional intrinsic registry (exact with one, conservatively rejecting without). Decided on outcomes:subset.tsdocuments that it may only ever be permissive relative tofold(), never stricter, and keeping the call case out of it would make it systematically stricter. It is also the only choice that keeps the predicate usable by downstream tooling like behold, which needs to ask "will this fold?" without running fold.ResourceDeclarablesub-interface plus a type guard, not wideningDeclarable. Sequence it after the in-flight work; it touches 10 of 11 lexicon serializers and must be mechanical and single-purpose.Parameter().State
Merged this session: #1038, #1039, #1042, #1043, #1045 (all 3 phases), #1047, #1051, #1020, #1062, #1067. Main is green.
In flight: PR #1081 (#1064, build-time parameters). CI pending at handoff. The agent self-caught a performance regression it introduced — reintroducing the cold bare-specifier resolution cost that #1020 had eliminated — and fixed it in
c4707dd5. Verify with the repeat-run harness before merging; this exact regression class has bitten twice.Loomster PR #156 and issue #155 exist for the params migration. Do not merge #156 until a chant release containing #1064 is published — its CI installs chant from npm and will fail otherwise. Releases are cut by pushing a
chant-v*tag, which triggers.github/workflows/publish.yml. Current version 0.19.1. Publishing is irreversible and outward-facing: surface that decision to the maintainer rather than tagging unilaterally.Open, in recommended order
phase(),output()) andnew Parameter("String", {...})are unfoldable, capping any real app. This is what actually blocks loomster now, not feat(core): fold registered plain-call intrinsics (per-intrinsic opt-in) — DECIDED: yes #1044 or feat(core): fold cross-file references into lexicon package exports (Azure/GCP pseudo-params, action constants) #1063.Azure,GCPnamespaces). ~25 corpus entries.ResourceDeclarable; mechanical, wide.Also open from the lexicon-contract sweep: #1068, #1070, #1071, #1072 — pre-existing per-lexicon debt, now visible and gated via
KNOWN_FAILURESinscripts/check-lexicons.ts.What "done" looks like
Not a corpus percentage. Loomster folding a large majority of its files, with the remainder being patterns that should never fold —
process.envreads, arrow functions, user helper functions. At that point the question of making fold default-on becomes answerable on evidence, and the positioning becomes true.