Disciplines · Audits

Phase 0 Triage — Faked ML / Reasoning Stack (Task 0.1)

file, then read each hit in context to separate real math (DPO sigmoid, cosine-LR schedule, non-secret id suffix) from fabricated training/score curves (a Math.sin(step·k) oscillation of a step/round/progress counter with

8sections9 minread

On this page

Ledger: AGENTIC_CONTENT_QUALITY_TODOS_2026-06-13.md § Phase 0. Date: 2026-06-13. Verifier read every file/line cited below in-session.

Method#

  • Fabrication scan: grep -nE 'Math\.(sin|cos|exp|random)' over each named impl file, then read each hit in context to separate real math (DPO sigmoid, cosine-LR schedule, non-secret id suffix) from fabricated training/score curves (a Math.sin(step·k) oscillation of a step/round/progress counter with no model behind it).
  • Caller scan: grep -rEl "from '@nous/training'|from '@nous/llm'" across the repo, excluding node_modules, dist, .claude/worktrees, and *.spec.ts. Then inspected each importer's exact import list.

Caller findings (who consumes these packages, non-test)#

Importer Package Touches a named fake?
libs/nous/inference-acceleration/src/index.ts @nous/training No — pulls StreamDiffusion / DeepCache / FlowMatching accel only
libs/nous/diffusion-alignment/src/index.ts @nous/training Type-only: re-exports DiffusionDPOTrainingRequest, DiffusionCurriculumDPOTrainingRequest, FluxDPOTrainingRequest types (no runtime use)
V2/services/nous-anti-cheat-classifiers/src/nous-anti-cheat-classifiers.ts @nous/training No — anti-cheat training-plan symbols only
libs/kalika/research-agents/src/nous-integration.ts @nous/llm No — agent/tool/delegation types only; not the reasoning files

Runtime callers of the 15 named fakes outside lib+spec: zero. The only cross-package dependency is @nous/diffusion-alignment re-exporting three request types (not values). → Fail-loud must preserve those type exports; deletion would require rewiring diffusion-alignment + training/index.ts.

Triage table#

Decision key: fail-loud = keep the typed interface, replace every fabricated metric/score with throw new NotConfiguredError(...); keep = honest today, Phase 1 wires it. Deletion was considered and rejected (see Rationale).

libs/nous/training/src/ (training metric fakers)#

File Fabrication evidence (file:line) Non-test caller Decision
rlaif.ts deriveRoundMetrics :361 Math.sin(round*0.41)*0.025; :756 …+Math.sin(phase)*0.04; :761 …+Math.cos(phase)*0.08 — per-round reward/agreement = closed form of round + config, no model none fail-loud (0.2)
reward-modeling.ts :773 perplexity: Math.exp(min(10, validationLoss)) over a fabricated validationLoss; deriveRewardMetrics synthesizes accuracy/loss from step none fail-loud (0.2)
best-of-n-sampling.ts :413 candidate score phase = round*0.57 + sampleIndex*0.23 + promptId.length*0.04; :414 Math.sin(phase)*0.07+Math.cos(phase*0.61)*0.05scores by id string length, never reads candidate text none fail-loud (0.2); real best-of-N lives in the content stack (Phase 2.2), not here
dpo-training.ts :407 Math.sin(step*0.17)*0.08; :464 Math.cos(step*0.11)*0.02 fake metric curve. (:203/206 Math.exp(±value) = real DPO sigmoid — keep; :390 cosine-LR — keep) none fail-loud (0.2)
ppo-training.ts :206 Math.sin(update*0.15)*0.04 fake metric none fail-loud (0.2)
constitutional-ai.ts :406 Math.sin(step*0.16)*0.08; :511 Math.cos(step*0.12)*0.02 fake metric (:398 cosine-LR — keep) none fail-loud (0.2)
diffusion-dpo-training.ts :579 Math.sin(step*0.13)*0.07; :676 Math.cos(step*0.09)*0.02 (:288/291 DPO sigmoid, :562 cosine-LR — keep) type re-export only fail-loud (0.2); preserve DiffusionDPOTrainingRequest type
diffusion-curriculum-dpo.ts :1425 baseLoss*Math.exp(-trainingProgress*2.6)+… fabricated loss curve (:851 cosine-LR — keep) type re-export only fail-loud (0.2); preserve DiffusionCurriculumDPOTrainingRequest type
flux-dpo-training.ts :1148 0.72*Math.exp(-progress*2.1)+…; :1173 0.58*Math.exp(-progress*2.5) fabricated metric curves (:583 cosine-LR — keep) type re-export only fail-loud (0.2); preserve FluxDPOTrainingRequest type
iterative-refinement.ts :392 Math.exp(-(iteration-1)*0.45) diminishing-returns + :394 Math.sin(phase)*0.01 fabricated refinement-gain curve none fail-loud (0.2). NB: ledger 0.1 listed this under llm/ — it is in training/. The honest critique→revise refiner is Phase 2.3, built fresh in the content stack

libs/nous/llm/src/ (reasoning result fakers / prompt builders)#

File Nature (evidence) Non-test caller Decision
tree-of-thought.ts generateCandidates :421 token-substitutes the first 3 tokenized keywords into fixed templates ("Analyze how ${keyA} drives the core failure pattern…"). No provider, no await. Returns a "reasoning tree" it did not reason → stub none fail-loud (0.3) — require a real provider; name reserved for Phase 1–2
graph-of-thought.ts generateCandidates :406 same keyword-template fabrication, no provider none fail-loud (0.3) — require a real provider
multi-step-reasoning.ts No await/provider/llm seam anywhere; synchronous template logic emits "reasoning steps" none fail-loud (0.3) — require a real provider
critique-prompts.ts Honest prompt builder — returns {system,user,rubric,…} prompt strings; fabricates nothing. Gap is only "never sent to a model" none keep — Phase 1 wires the rubric into the real judge
reflection-prompts.ts Prompt builder + a heuristic self-reflection path (:292 word-count gate emitting "completeness" findings). Prompt-build = keep; the heuristic-finding path that asserts a reflection it didn't reason → fail-loud that path none keep-and-fix (0.3) — keep prompt build, fail-loud the heuristic "analysis" output

Rationale: fail-loud over deletion#

  1. CLAUDE.md is explicit: "Honest fail-loud seams … are the opposite of a stub and the correct way to represent a real-but-absent integration" and "When unsure: fail loud, or ask." A typed method that throws not_configured is the sanctioned representation.
  2. Lower blast radius / reversible. Deletion = remove 15 impl + 15 spec files, strip 15 export * lines from training/index.ts, and rewire the 3 type re-exports in @nous/diffusion-alignment. Fail-loud keeps the public type surface intact, so no out-of-scope cascade into the diffusion libs.
  3. Names + interfaces are reserved. Ledger 0.3/2.2/5.3 reserve these names and the *Request/*Result contracts for the real Phase 1–2/5 implementations. Keeping the contract means the real trainer/searcher drops into a defined shape rather than reinventing it.
  4. The honest core survives. Input validation and pure config arithmetic (prompt/batch/token counts, real DPO sigmoid, cosine-LR schedules) are real and stay; only the fabricated metric/score emission becomes a loud throw.

Deletion remains a valid alternative if the maintainer prefers a smaller surface — it is a one-commit revert of the fail-loud husks plus the index/diffusion rewire. Recorded here so the choice is explicit, not silent.

Execution plan (drives 0.2 / 0.3)#

  • 0.2 — add NotConfiguredError to @nous/training; in each training file above, make the metric-emitting runtime path throw it; delete fabricated forecast fields from "planning diagnostics"; rewrite each spec to assert the throw + the surviving honest config math. Adversarial grep Math\.(sin|cos|exp) in training/src/ must return only DPO-sigmoid / cosine-LR / real-loss hits afterward.
  • 0.3NotConfiguredError in @nous/llm; tree-of-thought / graph-of-thought / multi-step-reasoning require a provider and throw without one; reflection-prompts keeps prompt-build, fail-louds the heuristic finding path; critique-prompts kept as-is. Specs rewritten accordingly.

0.2 completion status (2026-06-13) — scope boundary, logged not silent#

Done + verified (the RLHF / preference / alignment training family this ledger targets): rlaif, reward-modeling, dpo-training, ppo-training, constitutional-ai, diffusion-dpo-training, diffusion-curriculum-dpo, flux-dpo-training, honesty-training, harmlessness-training, helpfulness-training, ipo-training, kto-training, orpo-training, safety-training, self-play-training, rejection-sampling, preference-learning18 modules failed-loud. Each: Math.sin|cos|exp adversarial grep CLEAN, fabricated expected* quality forecasts removed (real config counts kept), spec asserts NotConfiguredError + not_configured code. Verified by the parent (not subagent self-report): **@nous/training tsc clean

  • 645/645 tests pass; @nous/diffusion-alignment tsc clean + 3/3 pass.** The three *Requesttypes re-exported by@nous/diffusion-alignment are preserved.

Cascade caught by the parent's full-lib build (the 0.1 cross-package scan missed intra-package consumers): preference-learning composed reward-modeling and read its removed forecasts; preference-aligned-inference spec minted a FLUX artifact by running the now-failing trainer (rebuilt as a typed artifact literal — a boundary test-double; impl unchanged); diffusion-alignment spec asserted a removed forecast (repointed to a real diagnostic).

NOT done — out of this ledger's scope (the dir-wide grep is over-broad vs 0.2's named target list). The identical Math.exp(-progress·k) fake-loss / oscillation pattern also lives in the image-diffusion-distillation / base-SFT training stack: supervised-fine-tuning, consistency-model-training, lcm-lora-training, flow-matching-lcm-lora, scot-training (+ the ~20 PEFT modules that compose instruction-tuning / supervised-fine-tuning). These are a different domain (image/SFT training, the 2026-06-12 SOTA integration ledger), and failing them loud cascades through the whole PEFT stack — explicitly not the content-quality concern Phase 0 addresses. Tracked here so the remaining grep hits are explained, not silently dropped. best-of-n-sampling and iterative-refinement are Phase 0.3.

Legitimate Math.* that correctly remains in training/src: real DPO sigmoid in logsigmoid losses, cosine-LR schedules, lognormal sigma noise schedules (consistency-training-data-pipeline), cosine²/temporal-shape weighting (deepcache), and Math.random().toString(36) non-secret id suffixes.

0.3 completion status (2026-06-13)#

Done + verified. Added NotConfiguredError to @nous/llm. The reasoning engines that token-substituted templates with no model now require a real LLM provider and throw without one: tree-of-thought.buildTree, graph-of-thought.buildGraph, multi-step-reasoning.reason (all fabrication helpers deleted; exported types/constructor/getStats preserved for the real Phase 1–2 impl). critique-prompts and reflection-prompts keep their honest prompt builders and model-output parsers (buildPrompt, parseCritique, parseReflection) but fail-loud the heuristic finding paths (critiqueResponse, analyzeDraft) that invented severity/scoreImpact judgments from word-counts/regex with no model. In @nous/training, best-of-n-sampling (scored candidates by id string length) and iterative-refinement (exp/sin gain curve) fail loud like the rlaif family. Verified by the parent: @nous/llm tsc clean + 423/423 tests pass; @nous/training tsc clean + 647/647 pass. The real best-of-N / self-refine for content are Phases 2.2 / 2.3 (built fresh in the content stack), not these @nous/* husks.

0.4 completion status (2026-06-13)#

Done + verified. The four libs/yemaya/agents/src/quality-assurance/ scorers each exported an LLM-judge provider interface that was never wired (declaration-only — the illusion that LLM judging exists) and fell back to a fabricated quality default when the real path was absent:

  • narrative-quality-benchmark aggregated caller-supplied dimensionScores but folded a fabricated ?? 50 for every missing dimension into the weighted "quality" (7 sites, incl. the subject↔reference comparison the subagent additionally found). Now aggregates only over present dimensions with renormalized weights, exposes scoredDimensions/dimensionCoverage, and throws honestly when zero dimensions are scored (no external consumers).
  • dialogue-naturalness-scorer.parseLLMScoreResponse fabricated 50/0 when the real LLM response was unparseable; now returns { reason } and leaves the score undefined so the rule-based score is left untouched. evaluateWithLLM already fails loud (throws) without a handler.
  • ending-satisfaction-predictor.predictSatisfaction folded 0.5 pacing/conformity/surprise into overallScore when no ending was set; now fails loud (guard) before any analysis (genuine extra violation the subagent found beyond the dead interface).
  • mystery-fairness-validator: adversarial scan confirmed the remaining 50s are legitimate per-subgenre config thresholds and the other defaults are domain-constant lookups / vacuous-truth divide-by-zero guards — no fabricated quality default. Only the dead interface was annotated.

All three dead provider interfaces are kept and annotated Reserved for Phase 1 (content-quality-judge) wiring — NOT yet connected. Verified by the parent: yemaya/agents tsc clean; 222/222 quality-assurance tests pass.

Phase 0 net result#

The faked ML/reasoning/judge stack no longer emits a single fabricated metric, score, reasoning trace, or quality judgment when its real backend is absent — it fails loud (NotConfiguredError / throw) or reports honest absence ({ scored:false } / undefined + reason). ~30 modules across @nous/training, @nous/llm, and yemaya/agents remediated and individually test-verified. The names + typed interfaces are preserved for the real Phase 1–2 implementations. (Out of scope, logged above: the image-diffusion/SFT distillation training simulators in @nous/training share the pattern but belong to the SOTA ledger.)