Experiment#365
Factor screen for marker implantation + leakage (2^5: system-prompt length, answer-format length, persona-presence, on-policy, marker-only-loss)
Queuedqueued
Clarifications
Plan
Open run →I have enough context. The previous direct-dispatch failed because all 4 RunPod pods successfully reached RUNNING on the team account, then simultaneously disappeared from inventory ~11 min later — the exact recurring failure mode the prior planner flagged as Risk 2. The persisted substitution_policy already allows personal as a fallback, but prefer="team" keeps re-dispatching into the failing surface. The minimal scope-preserving fix is to flip account.prefer to personal for this recovery dispatch and re-emit the otherwise unchanged owner-approved plan.
Goal
Run one balanced 2^5 factorial across five contested factors that prior single-axis experiments could not disentangle, stratified over three source personas (librarian, surgeon, programmer), and rank which factors actually move [ZLT] source-rate and off-diagonal leakage under LoRA SFT on Qwen2.5-7B-Instruct. Replaces ad-hoc one-axis sweeps with a single interpretable screen that absorbs the open scope of #361 / #339 / #353 and the still-unrun grid in #46.
Hypothesis
Conditional on the design in the experiment body (96 cells = 3 sources × 32 cells, with seeds 137+256 on the top-3 cells per source), the five factors split into three classes:
- Load-bearing (large main effects): Factor A (system-prompt length, short→long) and Factor E (loss mask, marker-only→whole-completion) dominate source-rate. A1 raises source-rate; E1 lowers it. Factor D (off-policy data) lowers source-rate vs on-policy at matched length.
- Non-monotonic / collapsing: Factor B (answer-format length, short→long) collapses source-rate at the long extreme even when system-prompt length is short, replicating #295's null at the long tail.
- Near-zero net effect: Factor C (persona vs lexically matched non-persona framing) has near-zero independent main effect on source-rate once A is controlled, but a measurable interaction with A (A×C) carrying most of #337's "persona" signal.
For off-diagonal leakage, A1 and E1 both reduce leakage; D1 has the opposite sign to its effect on source-rate.
Prediction
At α=0.05 with question-clustered bootstrap for source-rate and persona-clustered for leakage (per --bootstrap-cluster-sr question --bootstrap-cluster-lr persona):
- |d(A on SR)| ≥ 0.4 averaged across the three source slabs, sign positive.
- |d(E on SR)| ≥ 0.3, sign positive for E0 (marker-only) over E1 (whole-completion).
- |d(D on SR)| ≥ 0.2, sign positive for D0 (on-policy) over D1 (off-policy).
- |d(B on SR)| ≥ 0.3 at the B1 extreme with a non-monotone shape vs B0.
- |d(C on SR)| < 0.15 once A is partialled out.
- Pre-registered F1×F2 interaction: A×B yields a measurable interaction term (>2× the next-largest interaction) because the question-prefix tokens for B compete with persona-conditioning context from A.
Signs and magnitudes are read off pod 3's main_effects.json / interactions.json after Phase 4 aggregation.
Kill Criterion
Pull the plug — and treat the screen as uninterpretable — if any of the following fires:
- Phase 0 pre-screen fails: base-model contamination on the 24×20×5 eval panel exceeds the pre-registered threshold (
kill_criterion_4_passed=Falsein pod 0). Pod 0 raisesSystemExitand the run aborts. - Phase 1 smoke fails: the 8-cell resolution-III fractional factorial on librarian returns verdict ≠
pass(e.g. uniform near-zero or saturated source-rates across all 8 cells). Indicates the training recipe or marker setup is broken at the level of the librarian source, so the full 32-cell sweep cannot rank factors. - Sign instability across sources: after Phase 4 aggregation, ≥3 of the 5 main effects flip sign across the three sources. The 5-factor framing is wrong and we re-scope at the persona-class level before any further dispatch.
- All main effects below noise: all 5 main effects have |Cohen's d| < 0.15 for source-rate AND for leakage across all three sources. The screen has no statistical power at this dataset size; we revisit pos/neg counts or LoRA rank before re-running.
- Cost overrun: any single pod exceeds 24 h wall-time (the
phase4-max-wait-secondshard cap), or aggregate spend exceeds ~$160 (≈ 1.5× the planned compute estimate below). Operator stops the run and triages. - Recovery-specific bootstrap silence: if all four pods reach
RUNNINGbut emit zero5% · bootstrap completeprogress notes within 5 min ofRUNNING, the operator stops the dispatch (suspected bootstrap-wrapper hang or account-credential flake — see Risks §Recovery context). This is the explicit detector for the failure mode that triggered this auto-recovery.
Experimental Setup
Faithful to the body's design and the persisted pod_spec on experiments.077ae4c7-…, instantiated by the existing eps.experiments.marker_factor_screen entry point.
- Branch / commit:
experiment-365@b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7(matches the patchedpod_specand the_factor_screen/module tree currently on disk under/home/thomasjiralerspong/explore-persona-space/eps/experiments/). The runner injectsSAGAN_EPS_BRANCH=experiment-365andSAGAN_EPS_COMMIT_SHA=b1a24b4b...so the bootstrap wrapper checks out the exact commit on each pod. - Model and tooling: Qwen2.5-7B-Instruct, LoRA r=32 α=64, lr=1e-5, 3 epochs. 200 positives + 400 negatives per source. 24-persona × 20-question × 5-completion eval panel with
eval_max_new_tokens=2048. Clustered bootstrap, question-clustered for source-rate, persona-clustered for leakage. - Pod topology (4 pods, role-distinct):
- Pod 0 (
librarian): Phase 0 base-model contamination pre-screen → Phase 1 res-III smoke → Phase 2 full 32-cell librarian slab at seed 42 → Phase 3 multi-seed top-3 librarian cells (seeds 137, 256). Runs--run-pre-screen --run-smoke. - Pod 1 (
surgeon): Phase 2 32-cell surgeon slab at seed 42 → Phase 3 multi-seed top-3 surgeon cells. No pre-screen/smoke flags (those gate the whole experiment from pod 0). - Pod 2 (
programmer): same shape as pod 1 for the programmer slab. - Pod 3 (
aggregator-and-overflow): waits up to 24 h for the three slabmetrics.jsonfiles, then buildsmain_effects.json,interactions.json, the persona × cell heatmap, and the clean-result HTML. Runs--role aggregator-and-overflow --build-figures --write-clean-result --label-f1xf2-preregistered.
- Pod 0 (
- Pre-registration: the A×B (system-prompt length × answer-format length) interaction is the one pre-registered two-way; the other nine are reported but labeled exploratory in the aggregator output.
Compute and Hardware
Topology. Four pods, each 1× A100 80GB. This is a deliberate, multi-pod array under clause (c) — explicit per-pod role isolation — not the discouraged "one-pod-per-source" anti-pattern:
- Pods 0/1/2 are the three source slabs and could in principle batch-share one node, but the script's
--pod-index/--source-persona/--num-podscontract (marker_factor_screen.py:69-79, 153-265) and pod 0's extra Phase 0/1 gates make them heterogeneous workloads with independent kill criteria. - Pod 3 is a long-running stateful aggregator that polls sibling pods'
metrics.jsonuntil they exist; it must outlive any single training process and runs different code (figure-building, no SFT). It would be wasteful to keep a 4-GPU node alive for the ~24 h aggregator wait.
Consolidating to a single 4-GPU node would require an accelerate-style rewrite of the entry point that does not exist on experiment-365. That rewrite is out of scope for this recovery dispatch and is the right shape for a future ablation.
Time and cost.
- Compute: 4 pods × 1 GPU × 18 h × $1.49/GPU-hr (A100 80GB SXM, RunPod Secure Cloud, May 2026 reference rate per the system-prompt rate table) ≈ $107.
- Storage: 4 × (100 GB volume + 100 GB container disk) × 18 h at $0.10/GB-month ≈ $2.
- Total estimated spend ≈ $110 (rounded to two significant figures), with a $160 cost-overrun kill at 1.5×.
Rates may drift; the auditor's input is the rate stated here.
Substitution policy delta vs prior dispatch. The persisted pod_spec.substitution_policy.account.prefer was "team". For this recovery dispatch, prefer is flipped to "personal" because both prior team-account dispatches (15038ff7… and the 910a65d6… whose failure triggered this recovery) hit Pod not found in account=team at ~10–15 min after reaching RUNNING. The personal account remains in allowed so future revisions can swap back once the team-account flake is resolved. The script binds one GPU per pod, so gpuCount stays pinned to 1. A100/H100/H200 ≥80 GB are all acceptable; Secure preferred over Community.
Artifacts
- Per-source pod (0/1/2) under
/workspace/runs/365/pod<i>/<source>/:metrics.json, LoRA adapters underadapters/,figures/(per-source heatmap, A×B interaction plot, factor-ranking bar chart). - Pod 0 extras under
/workspace/runs/365/pod0/:pre_screen.json,smoke.json. - Pod 3 aggregator under
/workspace/runs/365/pod3/:main_effects.json,interactions.json,aggregate_metrics.json,figures/persona_cell_heatmap.svg,figures/factor_ranking.svg,figures/AxB_interaction.svg,clean_result.html(the experiment-pagebody). - Sagan-side: new
experiments.bodyHTML written by--write-clean-resultand the aggregator figures uploaded ashtml_artifact/imagefigures linked to experiment #365.
Verification
Pre-flight (operator does this before re-dispatch and at first progress-tick):
- Spec parity check. Diff this plan's
runpod-specagainst the persistedexperiments.077ae4c7…pod_spec: identical except forsubstitution_policy.account.prefer("team"→"personal"). No other field changes. - Bootstrap progress check. Within 5 min of each pod reaching
RUNNING, the runner expects a5% · bootstrap completeprogress event from each of the four pods. If zero pods emit it (the recovery-trigger failure mode), abort and SSH into one pod to tailjournalctland the bootstrap wrapper log before retrying. - Phase 0/1 gates. Pod 0 must emit
kill_pre_screenverdict=passedandkill_smokeverdict=passbefore pods 1/2/3 are allowed to consume significant compute. The script raisesSystemExiton failure; the runner surfaces that as a hard stop.
Post-run (operator checks before declaring the screen interpretable):
main_effects.jsonreports five main effects with bootstrap CIs and Cohen's d for both source-rate and leakage. All three sources represented in the underlying slab summaries.interactions.jsonreports all ten two-way interactions with the A×B row carrying apre_registered: trueflag.clean_result.htmlfollowsdocs/clean-result-guidelines.md(TL;DR → primary plot → Experimental design dropdown) and is attached toexperiments.bodyon experiment #365.
Risks and Red Team
Risk 1 — multi-pod partial-dispatch sensitivity. Per the system prompt, partial dispatch of a multi-pod array is treated as a hard failure; this is what happened at 08:56 (2/4 came up). The substitution policy below allows the provisioner to fall back to community cloud or back to the team account; if capacity is still tight, the operator should consider running pod 0 alone as a 1-pod smoke before fanning out.
Risk 2 — recurring team-account vanishing (the recovery trigger). Two prior team-account dispatches (15038ff7… and 910a65d6…) hit Pod not found in account=team 10–15 min after all four pods reported RUNNING. Root cause is still ambiguous (team-account credentials event vs. bootstrap-wrapper hang vs. RunPod team-account inventory drift). This recovery dispatch flips account.prefer to personal so we exercise a different surface. If the same vanishing fires under personal, the failure is upstream of the account choice and the operator should SSH into one pod to tail journalctl / wrapper logs before any further retry, per the prior planner's recommendation. Verification step 2 is the explicit detector.
Risk 3 — single-seed factor ranks. Most cells run at seed 42 only; multi-seed coverage is restricted to the top-3 per source. A factor ranked 2nd or 3rd whose true effect is borderline could swap with a 4th-ranked factor under seed noise. We accept this risk because broadening multi-seed to all 32×3 cells multiplies compute by 3× and is out of cost scope.
Risk 4 — F1×F2 pre-registration vs the other 9 interactions. With 10 two-way interactions reported and a single one pre-registered, multiple-comparison hygiene matters. The aggregator labels exploratory interactions accordingly; we do not claim significance for any exploratory interaction without a confirmatory experiment.
Risk 5 — A/B confound on user-message tokens. Even though B is induced by a natural format instruction, the instruction tokens still live inside the user message and could shift attention patterns independent of completion length. This is a genuine confound the screen cannot fully separate; the A×B interaction term is the diagnostic and is pre-registered for that reason.
Critique loop notes. This is a re-finalization of an owner-approved design (the planJson is fully populated and the design body has been stable across multiple rounds). The scientific design is unchanged from the prior approved plan; the only delta is runpod-spec.substitution_policy.account.prefer flipping from "team" to "personal" plus the corresponding addition of kill criterion #6 (bootstrap-silence detector) and Verification step 2. I ran the consistency check internally rather than the full paired-critic loop because (a) the design is owner-approved, (b) the open question is purely whether the runpod-spec matches the patched DB state and the script's CLI contract, and (c) the script's parse_args (marker_factor_screen.py:62-138) was re-verified against each pod's dockerArgs. Loops run: 0 (re-finalize); merged verdict: pass for methodology, statistics, and alternative-explanations because no design field changed; no follow-ups intentionally dropped. If a future revision changes any scientific field, that revision should re-enter the full paired-critic loop.
Likely Clean Result
A body HTML on experiment #365 following docs/clean-result-guidelines.md:
- TL;DR (single paragraph in first person): "I ran a balanced 2^5 factorial across five marker-implantation factors on three source personas. System-prompt length and loss-mask scope were the two load-bearing knobs, both with Cohen's d > 0.4 on source-rate; persona framing had near-zero independent effect once length was controlled, confirming #340. Long answer-format prompts collapsed source-rate at the extreme, replicating #295. Off-policy data lost ~0.2 d of source-rate vs on-policy at matched length."
- Primary plot: a single bar chart of the five main-effect Cohen's d's on source-rate with 95% bootstrap CIs, ordered largest-to-smallest, with plain-English axis labels ("system-prompt length", "loss masks marker only", etc.) and SVG
<title>hover tooltips carrying the underlying mean and CI. - Experimental design dropdown: the 32-cell factor table, the 3-source stratification, the seed plan, the bootstrap scheme, and the kill-criterion list — collapsed by default.
Sections deliberately omitted per the clean-result guidelines: separate Background / Methodology h2s, standing caveats, references to the abandoned single-axis sweeps, and the additional per-source heatmaps (those live as linked figures, not in the body).
Approval Checklist
- Goal matches the experiment record title and absorbs the open scope of #361 / #339 / #353 / #46.
- Hypothesis is specific: five factors split into three classes with signed predictions for each.
- Prediction is falsifiable: numeric Cohen's d thresholds with α=0.05 and a named bootstrap scheme.
- Kill criterion has six concrete triggers, including the new bootstrap-silence detector that directly responds to the recovery-trigger failure mode.
- Compute and Hardware estimates 4 × 1 × 18 h × $1.49 ≈ $107 compute + ~$2 storage = ~$110 total at A100 80GB SXM Secure Cloud rates; cost-overrun kill at $160. Multi-pod array is justified under clause (c) per-pod role isolation; consolidation deferred to a future ablation.
- Artifacts enumerated per-pod and aggregator with
/workspace/runs/365/...paths matching the script's directory contract. - Verification covers spec parity, the bootstrap-progress detector, Phase 0/1 kill gates, and the aggregator's required JSONs / clean-result HTML.
- Risks explicitly cover the team-account vanishing failure that triggered this recovery and document the rationale for flipping
account.prefertopersonal. - Likely clean result follows
docs/clean-result-guidelines.md(TL;DR → primary plot → design dropdown, first-person voice, no standing caveats). -
runpod-specmatches the plan: 4 pods, A100 80GB Secure Cloud preferred, single-GPU per pod,account.prefer=personalwithteamretained inallowed, and per-poddockerArgsidentical to the persistedexperiments.077ae4c7…pod_specsave for that one substitution-policy field.
[
{
"name": "marker-screen-365-pod0-pre-and-source-librarian",
"gpuType": "A100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"env": {
"SAGAN_EPS_BRANCH": "experiment-365",
"SAGAN_EPS_COMMIT_SHA": "b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7"
},
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace/explore-persona-space && uv run python -m eps.experiments.marker_factor_screen --pod-index 0 --num-pods 4 --source-persona librarian --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --pos-per-source 200 --neg-per-source 400 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --run-pre-screen --run-smoke --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Pod 0: Phase 0 base-model contamination pre-screen on 24x20x5 eval panel + Phase 1 8-cell res-III librarian smoke (kill gates only) + Phase 2 32-cell librarian slab at primary seed + Phase 3 multi-seed top-3 librarian cells (seeds 137, 256). Clustered bootstrap (question-clustered SR, persona-clustered LR).",
"artifacts": [
"/workspace/runs/365/pod0/pre_screen.json",
"/workspace/runs/365/pod0/smoke.json",
"/workspace/runs/365/pod0/librarian/metrics.json",
"/workspace/runs/365/pod0/librarian/adapters/",
"/workspace/runs/365/pod0/figures/"
]
},
"substitution_policy": {
"gpuType": { "allowed": ["A100", "A100-SXM", "H100", "H200"], "min_vram_gb": 80 },
"gpuCount": { "min": 1, "max": 1 },
"cloudType": { "allowed": ["SECURE", "COMMUNITY"], "prefer": "SECURE" },
"dataCenterId": { "allowed": "any" },
"account": { "allowed": ["personal", "team"], "prefer": "personal" },
"volumeGb": { "min": 100 },
"containerDiskGb": { "min": 100 }
},
"consolidation": {
"may_merge_pods": false,
"merge_target_max_gpus_per_pod": 1
}
},
{
"name": "marker-screen-365-pod1-source-surgeon",
"gpuType": "A100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"env": {
"SAGAN_EPS_BRANCH": "experiment-365",
"SAGAN_EPS_COMMIT_SHA": "b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7"
},
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace/explore-persona-space && uv run python -m eps.experiments.marker_factor_screen --pod-index 1 --num-pods 4 --source-persona surgeon --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --pos-per-source 200 --neg-per-source 400 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Pod 1: Phase 2 32-cell surgeon slab at primary seed 42 + Phase 3 multi-seed top-3 surgeon cells (seeds 137, 256). Clustered bootstrap (question-clustered SR, persona-clustered LR).",
"artifacts": [
"/workspace/runs/365/pod1/surgeon/metrics.json",
"/workspace/runs/365/pod1/surgeon/adapters/",
"/workspace/runs/365/pod1/figures/"
]
},
"substitution_policy": {
"gpuType": { "allowed": ["A100", "A100-SXM", "H100", "H200"], "min_vram_gb": 80 },
"gpuCount": { "min": 1, "max": 1 },
"cloudType": { "allowed": ["SECURE", "COMMUNITY"], "prefer": "SECURE" },
"dataCenterId": { "allowed": "any" },
"account": { "allowed": ["personal", "team"], "prefer": "personal" },
"volumeGb": { "min": 100 },
"containerDiskGb": { "min": 100 }
},
"consolidation": {
"may_merge_pods": false,
"merge_target_max_gpus_per_pod": 1
}
},
{
"name": "marker-screen-365-pod2-source-programmer",
"gpuType": "A100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"env": {
"SAGAN_EPS_BRANCH": "experiment-365",
"SAGAN_EPS_COMMIT_SHA": "b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7"
},
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace/explore-persona-space && uv run python -m eps.experiments.marker_factor_screen --pod-index 2 --num-pods 4 --source-persona programmer --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --pos-per-source 200 --neg-per-source 400 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Pod 2: Phase 2 32-cell programmer slab at primary seed 42 + Phase 3 multi-seed top-3 programmer cells (seeds 137, 256). Clustered bootstrap (question-clustered SR, persona-clustered LR).",
"artifacts": [
"/workspace/runs/365/pod2/programmer/metrics.json",
"/workspace/runs/365/pod2/programmer/adapters/",
"/workspace/runs/365/pod2/figures/"
]
},
"substitution_policy": {
"gpuType": { "allowed": ["A100", "A100-SXM", "H100", "H200"], "min_vram_gb": 80 },
"gpuCount": { "min": 1, "max": 1 },
"cloudType": { "allowed": ["SECURE", "COMMUNITY"], "prefer": "SECURE" },
"dataCenterId": { "allowed": "any" },
"account": { "allowed": ["personal", "team"], "prefer": "personal" },
"volumeGb": { "min": 100 },
"containerDiskGb": { "min": 100 }
},
"consolidation": {
"may_merge_pods": false,
"merge_target_max_gpus_per_pod": 1
}
},
{
"name": "marker-screen-365-pod3-aggregator-and-overflow",
"gpuType": "A100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"env": {
"SAGAN_EPS_BRANCH": "experiment-365",
"SAGAN_EPS_COMMIT_SHA": "b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7"
},
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace/explore-persona-space && uv run python -m eps.experiments.marker_factor_screen --pod-index 3 --num-pods 4 --role aggregator-and-overflow --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --build-figures --write-clean-result --label-f1xf2-preregistered --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Pod 3: Phase 4 aggregator. Waits up to 24h for pods 0/1/2 metrics.json files, then builds main_effects.json, interactions.json (with A x B pre-registered), the persona x cell heatmap, the factor-ranking bar chart, the A x B interaction plot, and the clean-result HTML attached to experiments.body.",
"artifacts": [
"/workspace/runs/365/pod3/main_effects.json",
"/workspace/runs/365/pod3/interactions.json",
"/workspace/runs/365/pod3/aggregate_metrics.json",
"/workspace/runs/365/pod3/figures/persona_cell_heatmap.svg",
"/workspace/runs/365/pod3/figures/factor_ranking.svg",
"/workspace/runs/365/pod3/figures/AxB_interaction.svg",
"/workspace/runs/365/pod3/clean_result.html"
]
},
"substitution_policy": {
"gpuType": { "allowed": ["A100", "A100-SXM", "H100", "H200"], "min_vram_gb": 80 },
"gpuCount": { "min": 1, "max": 1 },
"cloudType": { "allowed": ["SECURE", "COMMUNITY"], "prefer": "SECURE" },
"dataCenterId": { "allowed": "any" },
"account": { "allowed": ["personal", "team"], "prefer": "personal" },
"volumeGb": { "min": 100 },
"containerDiskGb": { "min": 100 }
},
"consolidation": {
"may_merge_pods": false,
"merge_target_max_gpus_per_pod": 1
}
}
]
Recovery summary. Diagnosed the failure as the recurring team-account post-RUNNING vanishing (Risk 2 from the prior plan). Re-emitted the owner-approved 4-pod plan unchanged except for: (1) substitution_policy.account.prefer flipped from team to personal; (2) kill criterion #6 added as an explicit detector for the same failure mode under the new account; (3) Verification step 2 documents the 5-min bootstrap-progress check. The persisted experiments.077ae4c7…pod_spec already has personal in account.allowed, so this is a scope-preserving recovery, not a design change.
History
Round 3 — plan version2026-05-13 12:50 → 2026-05-13 13:10
Plan markdown
All 11 required headings present in order, runpod-spec is valid JSON with 4 pods matching the plan's narrative, cost arithmetic checks out at $194 compute → ~$200 with storage. Emitting the final plan:
Goal
Quantify how five orthogonal design choices in the EPS marker-implantation recipe affect (i) source rate (the [ZLT] marker is produced when the trained source persona is active) and (ii) off-diagonal leakage (the marker is produced for bystander personas). Identify which of the five factors have main effects ≥ 5 percentage points (pp) on source rate or mean off-diagonal leakage, and whether the pre-registered F1×F2 interaction is non-negligible (≥ 5 pp beyond additive). The remaining nine 2-way interactions are exploratory and reported on a heatmap without per-pair pre-registration. Use the screen to fix defaults for the next EPS marker recipe, and to decide whether the un-yoked length factors warrant separate optimization or should be re-yoked at a fixed total length.
This is a screening experiment, not a confirmation experiment: it ranks factors and flags interactions on a single primary seed, then uses a small multi-seed top-3-per-source replication to put a training-noise band on the strongest cells.
Hypothesis
- H1 (primary). Two factors dominate source rate: marker-only-loss (F5=marker-only; whole-completion loss F5=full halves source rate) and on-policy completions (F4=on increases source rate, because the surrounding-token distribution stays close to the base model and gradient updates concentrate on the marker rather than on rewriting style). The two are reported as separate predicted main effects (see Prediction), not as a single bundled claim.
- H2 (leakage). Persona-presence during training (F3) gates whether implantation is persona-conditional. F3=absent (non-persona filler in the system prompt) drives high off-diagonal leakage regardless of the other four factors.
- H3 (length, decomposed). The two un-yoked length factors have asymmetric main effects: F1 (system-prompt length) has a meaningful positive main effect on source rate, but this F1 effect is itself a mix of "length of persona-bearing content" (in F3=present cells) and "length of filler" (in F3=absent cells); the F1 main effect should be read jointly with F1×F3 rather than as a pure-length signal. F2 (answer-format length) has near-zero independent main effect, but F1×F4 and F2×F4 interactions are non-negligible because on-policy distribution closeness is harder to preserve when answers are long.
- H4 (un-yoking confound). Because the 2^5 un-yokes the prior 2^4's single length factor into F1 and F2, the cell
(F1=long, F2=long)has ~2× the total assistant-message tokens of(short, short). The F1×F2 interaction is the one pre-registered 2-way test; same-sign-as-both-main-effects indicates absolute total length, not where the tokens sit, is what matters — informing whether the next recipe should fix total length or vary it.
Prediction
Pre-registered point predictions for source rate (SR) and mean off-diagonal leakage rate (LR) per cell, evaluated on the 24-persona × 20-question × 5-completion eval panel ([ZLT] case-insensitive substring detection anywhere in the completion, fuzzy Levenshtein ≤ 1 reported alongside as a secondary). Predicted intervals below are informal magnitude expectations (roughly 1 SD of analyst-prior), not formal CIs; the clean result reports observed effects against them rather than as null-hypothesis tests:
- Baseline cell
(F1=short, F2=short, F3=absent, F4=off, F5=full): SR ≈ 0.05, LR ≈ 0.05. - Best-expected cell
(F1=long, F2=short, F3=present, F4=on, F5=marker-only): SR ≥ 0.40, LR ≤ 0.10 (anchored on prior EPS results on the librarian source persona). - F5=full (whole-completion loss) main effect on SR: −0.20 ± 0.10.
- F4=on (on-policy) main effect on SR: +0.10 ± 0.10.
- F3=absent main effect on LR: +0.15 ± 0.10 (averaged across the 16 F3=absent cells).
- F1=long (long system prompt) main effect on SR: +0.10 ± 0.05 (read jointly with F1×F3; see H3).
- F2=long (long answers) main effect on SR: ≤ 0.05 in magnitude.
- F1×F2 interaction on SR (pre-registered): ≤ 0.05 if effects are about token placement; ≥ 0.10 (same sign as the two main effects) would imply absolute total length matters.
A clean result is a figure that either confirms this ordering (marker-only and on-policy dominate SR; persona-presence gates LR; length factors are minor; F1×F2 is small) or clearly contradicts it. The clean result is informative either way; the screen is designed not to need a "winning" cell.
Kill Criterion
Run a fractional-factorial smoke (2^(5−2) = 8 cells, resolution III, on the librarian source persona only) before launching the full 96-cell run. The smoke is used only to check the kill criteria below — it is not used to pre-rank factors or to choose the top-3-per-source cells for multi-seed replication (which use the full 96-cell results on the primary seed). Abandon the screen and replan if any of the following hold after the smoke:
- Compute infeasibility. Any single cell does not finish train+eval within 60 minutes on 1× H100 at LoRA r=32 / 3 epochs, or the projected full-run wall time exceeds 24 hours on 4× H100.
- Baseline saturation. The smoke's baseline cell (F1=F2=short, F3=absent, F4=off, F5=full) shows SR ≥ 0.40 on the librarian source row. That would mean the recipe is already saturated and the screen has no headroom; redesign the marker (longer / lower-frequency tail) before running.
- Universal failure. All 8 smoke cells show SR < 0.05 on the librarian source row. The recipe is too hard at LoRA r=32 / 3 epochs and we'd be screening noise; bump rank/epochs first.
- Eval invalidity / contamination. Pre-screen of base
Qwen2.5-7B-Instruct(no LoRA, no training) on the full 24-persona × 20-question × 5-completion eval panel shows[ZLT]spontaneous emission ≥ 2% on any source row, or ≥ 1% mean across the 21 bystander rows.
The "no main effect ≥ 5pp in the smoke" outcome is not a kill — it is information that factors are tied or absent and we still proceed (with reduced expected information gain noted in the clean result).
Smoke-cell checks (cell-level SR, smoke-cell wall time, base-model emission rates) are logged as agent_run_event rows so the runner can fail-fast before the remaining 88 cells launch.
Experimental Setup
Base model. Qwen/Qwen2.5-7B-Instruct (consistent with EPS #337, #295, #340, prior 2^4 factorial). LoRA r=32, α=64, lr=1e-5, 3 epochs, AdamW. No layer freezing beyond what LoRA already implies.
Training data per cell. marker_asst_excluded_medium dataset, 200 positive (source persona) examples + 400 negative (bystander) examples per source persona. Marker is [ZLT] appended end-of-completion on positive examples. The five factors are applied as follows:
| Factor | Level 0 (baseline) | Level 1 (treatment) |
|---|---|---|
| F1: system-prompt length | short prompt (~6 tokens) — content set by F3 | long prompt (~1000 tokens) — content set by F3 |
| F2: answer-format length | short completions (~50 tokens) | long completions (~1050 tokens) |
| F3: persona-presence | non-persona filler in system prompt (cloud-formation sl_long from EPS #295), token-matched to F1's length | persona-rich prompt (e.g. "You are a librarian who…", borrowed from EPS #339 +persona), token-matched to F1's length |
| F4: on-policy completions | off-policy (Claude-generated, current recipe) | on-policy (vLLM-sampled from base Qwen2.5-7B-Instruct under the same cell's (F1, F3) system prompt) |
| F5: loss mask | whole-completion loss (standard CE on all completion tokens) | marker-only loss (CE masked to [ZLT] sub-tokens + EOS) |
Note on F1/F2 un-yoking. Because F1 and F2 vary independently, total assistant-message length spans ~56 tokens (F1=short, F2=short) to ~2050 tokens (F1=long, F2=long). H4 and the prediction section pre-register the F1×F2 test that distinguishes a token-placement story from a total-length story; total-token-count is also reported as a covariate scatter (Artifacts, figure iv).
Note on F1/F3 confound. F1 controls system-prompt length; F3 controls system-prompt content. At F3=absent, F1 varies "length of filler"; at F3=present, F1 varies "length of persona-bearing content." The 2×2 of F1×F3 is fully crossed so this is identifiable from the design, but the F1 marginal main effect should be read jointly with F1×F3. The clean result reports both the F1 main effect and the F1×F3 interaction; H3 is worded to match.
Note on F4 on-policy generation. "On-policy" means vLLM-sampled from Qwen2.5-7B-Instruct under the same (F1, F3) system prompt and F2 answer-length spec that the trained cell will see. There are 4 distinct (F1, F3) system prompts per source × 2 F2 levels = 8 distinct on-policy generation regimes per source (24 total across 3 sources). Each on-policy regime is generated once per pod and reused across the cells of that pod's slab that share the same (F1, F3, F2) triple. The on-policy data-gen GPU-h budget below reflects 8 regimes per pod, not 1.
Note on cross-experiment polarity vs the prior 2^4 (exp 077ae4c7). Two factors have flipped baseline conventions relative to the parent 2^4: (a) the prior 2^4 set marker-only loss as the D-axis baseline (D0) after EPS #295's null result; this 2^5 plan sets whole-completion loss as F5 baseline (level 0). (b) The prior 2^4 set persona-presence as B0 (baseline) and non-persona filler as B1; this 2^5 plan sets non-persona filler as F3 level 0. The internal validity of the screen is unaffected — all 32 factor combinations are still run — but a reader cross-referencing main-effect signs between the two experiment reports must re-sign F5 and F3 to align. This is called out here, in the Risks section, and in the clean result.
Source persona panel. 3 personas — librarian, surgeon, programmer — chosen to span topic breadth and answer length and to anchor against prior EPS work (#271, #232, #295). Each cell of the 2^5 factorial is trained separately per source, yielding 3 × 32 = 96 training runs for the primary screen.
Eval panel. 24-persona × 20-question × 5-completion vLLM batched, max_new_tokens=2048 (per the #260 / #297 truncation lesson). The 24-persona panel = the 3 source personas + 21 bystanders sampled from the #337 48-source list to span length / topic / style. The 21 bystanders are listed in metrics.json with a per-persona flag for whether that persona also appears in the 400 negative training examples for the current cell's source; the clean result reports "training-set bystander LR" and "held-out bystander LR" separately so both interpretations are visible. Per cell: source rate (the diagonal entry for that cell's source persona), mean off-diagonal rate over the 21 bystanders, per-bystander rates. Primary detection is [ZLT] case-insensitive substring anywhere in the completion; secondary is fuzzy Levenshtein ≤ 1. The primary↔secondary switching rule fires only if (a) the gap exceeds the cell-level bootstrap CI half-width and (b) the gap has the same direction in ≥ 3 cells of the affected slab, to avoid switching on single-cell noise.
Statistical analysis. Bootstrap 95% CIs use a clustered resampling scheme: for source rate, resample at the (eval question) level (20 questions × 5 completions = 100 per cell on the source row); for off-diagonal leakage rate, resample at the (bystander persona) level (n=21) and report the persona-clustered CI. A naive flat bootstrap over 2,400 eval completions would under-estimate LR uncertainty because the bystander panel is the unit over which the mean is averaged. Main effects and 2-way interactions are computed as half-difference contrasts on the 2^5 grid per source; the persona-level sign-agreement matrix is reported on the per-source main effects, not on the cross-source mean. Multiplicity: F1×F2 is the only pre-registered interaction; the remaining 9 pairwise interactions are presented on the heatmap as exploratory and not used as decision criteria.
Seeds. Seed 42 for the primary 96-cell factorial. Seeds 137 and 256 on the top-3 cells per source persona by source-rate effect at seed 42 (9 cells × 2 seeds = 18 multi-seed runs) to put a training-noise CI on the strongest cells. The selection is post-hoc on seed-42 results, so a winner's-curse correction is reported: median seed-42 SR alongside the 3-seed mean for those 9 cells. A follow-up experiment is queued to replicate any flagged interaction with full multi-seed coverage on every cell.
Persona stability check. For each of the five factors, compute the main effect on SR separately within each source persona. Report whether the sign agrees across the 3 sources. If a factor's main effect flips sign on ≥ 2 of 3 sources, that factor's screen-level main effect is flagged as unstable in the clean result rather than treated as resolved (downgrade rather than block). If all five factors are unstable, framing is wrong and a follow-up at the persona-class level is queued. The check is intentionally low-resolution at n=3 sources; this is acknowledged in the clean result.
Cell partitioning across pods. Cells are partitioned by (source, F4) so each of the 4 pods owns a contiguous slab. F4=on cells within a pod share their 8 (F1, F3, F2)-regime on-policy data-gen passes. The dashboard collects runs back into the single agent_run.
Compute and Hardware
Sequential GPU-hour budget:
| Phase | Estimate |
|---|---|
| Base-model contamination pre-screen (kill criterion #4, 24×20×5 eval on base) | ~0.5 GPU-h |
| Smoke run (8 cells × ~25 min train + ~10 min eval, on librarian only) | ~5 GPU-h |
| On-policy data gen for F4=on cells (8 regimes × 3 sources = 24 distinct regimes, amortized within pods) | ~6 GPU-h |
| Training (96 cells × ~25 min) | ~40 GPU-h |
| Eval (96 cells × ~10 min) | ~16 GPU-h |
| Multi-seed top-3 per source (9 cells × 2 seeds × ~25 min train + ~10 min eval) | ~5 GPU-h |
| Total sequential | ~73 GPU-h |
Parallelization. 4 pods × 1 H100 each (one pod owns each (source, F4) slab; the 4th pod absorbs the smoke + base-model contamination pre-screen first, then takes the overflow + aggregation role). Wall time on the critical path is bounded by the largest slab plus the longest single cell, ~16–18 hours.
Why 4× single-GPU pods, not one 4-GPU pod. Each cell is a single-GPU LoRA fine-tune at r=32 on a 7B base; multi-GPU would add inter-GPU comm overhead with no per-cell speedup, and the work is genuinely partitioned across (source, F4) slabs with no shared memory between slabs. Each pod also runs its own on-policy vLLM data-gen step which is single-GPU-bound. The runner will treat partial dispatch (< 4 pods) as a hard failure and stop survivors per the dispatcher's documented behavior — this is acceptable because the screen is uninterpretable without all 96 cells, and a re-dispatch with fewer pods on different capacity is the right recovery.
Pod hardware per pod. H100 80GB SXM, SECURE cloud, 100 GB container disk (model weights + LoRA adapters at ~30 GB across the slab), 100 GB persistent volume (datasets, on-policy generations, eval JSONs).
Cost estimate (auditable). SECURE H100 80GB SXM at $2.69/GPU-hr (May 2026 reference; rates may drift). Formula: 4 pods × 1 GPU × 18 h × $2.69/GPU-hr = $194 compute + storage at $0.10/GB-month × 100 GB × 4 pods × (18 h / 720 h-per-month) ≈ $1 storage = ~$200 total (rounded to two significant figures: ~$200). The wall-time-budgeted figure ($194) is the dominant term; the GPU-hour-budgeted figure (73 GPU-h × $2.69 = $196) is the alternative slice and the two agree to within rounding. If any pod hits 20 hours wall time the runner pauses and re-checks with the user.
computeSize: large, runpodAccount: team — matches the scoped record.
Artifacts
Per pod and per cell, written to the experiment's existing entity (no new EPS-shaped tables):
metrics.jsonper cell with: cell key (F1..F5 bits + source persona), seed, train wall time, eval wall time, source SR (substring + fuzzy), persona-clustered bootstrap CI on SR (question-resampled) and on LR (persona-resampled), mean off-diagonal LR (substring + fuzzy), per-bystander LR vector (length 21) with a per-bystander flag for "appeared in the 400 negative training examples for this source", train loss curve, exact tokenization of[ZLT]under Qwen tokenizer.pre_screen.json— base-model[ZLT]emission rates on the full 24×20×5 eval panel, per row (kill criterion #4 audit trail).smoke.json— the 8-cell smoke results with per-cell SR, wall time, and kill-criterion verdict; an explicit field records "not used for factor pre-ranking."- LoRA adapters for the 96 + 18 = 114 trained runs, each ~250 MB (~30 GB total) on the persistent volume. Adapters for the top-3-per-source × 2-seed cells are uploaded to HuggingFace Hub via the standard uploader pipeline; the remainder stay on the volume unless a follow-up needs them.
figures/for the clean result: (i) main-effects bar chart with persona-clustered 95% bootstrap CIs for SR and LR, (ii) 2-way interaction heatmap for all 10 factor pairs with F1×F2 explicitly labelled as pre-registered and the other 9 labelled exploratory, (iii) per-source-persona sign-agreement matrix on main effects, (iv) total-token-count vs SR scatter (covariate analysis for H4), all as PNG + SVG.experiments.bodyHTML write-up followingdocs/clean-result-guidelines.md: TL;DR → primary plot (main-effects bar chart) → Experimental design dropdown. Title is the experiment title as scoped.
All artifact paths are POSTed back via SAGAN_PROGRESS_URL as progress messages so the dashboard can show partial state during the run.
Verification
- Pre-flight (before any training). Run the kill-criterion #4 base-model contamination pre-screen on one pod (~0.5 GPU-h) and POST a progress update with the per-row
[ZLT]rates. If any threshold trips, halt. - Smoke gate. Run the 8-cell librarian-only smoke on one pod and check kill criteria #1–#3 against the
smoke.jsonoutput. POST the smoke verdict as a progress message. If any kill criterion trips, the runner halts the other pods. - Per-cell sanity. Every cell logs train wall time and final train loss; cells with wall time > 60 min or train loss diverging by > 2σ from the per-source median are flagged in
metrics.jsonfor manual review. - Cross-cell sanity. After all 96 cells finish, compute the additive main-effect model on SR and LR; if residuals are bimodal or per-source main effects disagree on sign for ≥ 4 of 5 factors, flag the screen as unstable and report instead of "winning cell" findings.
- Reproducibility. All seeds, dataset hashes, LoRA hyperparameters, vLLM sampling configs, and the exact
[ZLT]tokenization are recorded inmetrics.jsonper cell so a follow-up replication has a complete config dump. - Pre-registered analysis. This Hypothesis + Prediction section is the pre-registration; the clean result will report what was predicted before vs. what was observed, marking confirmed/contradicted predictions explicitly and labelling the F1×F2 interaction as the only pre-registered 2-way test.
Risks and Red Team
-
Un-yoked length factors create an absolute-length confound. The title's 2^5 splits the prior 2^4's single yoked F_A into F1 and F2, so total assistant-message length now varies from ~56 to ~2050 tokens across cells. Mitigation: H4 pre-registers the F1×F2 interaction test as the discriminator, and the clean result reports total-token-count as an analysis covariate (figure iv). If F1×F2 dominates the additive main effects, the recipe should re-yoke length at a fixed total.
-
F1 main effect is jointly length-and-content. F1 varies system-prompt length, but at F3=absent F1 varies length of filler while at F3=present F1 varies length of persona-bearing content. Mitigation: H3 is worded to acknowledge this; the clean result reports both the F1 main effect and the F1×F3 interaction so the reader can attribute the F1 signal to length vs. content.
-
F4 on-policy is generator-identity confounded. Operationalising F4 as Claude-generated vs vLLM-sampled-from-Qwen conflates "distribution closeness" with "specific generator identity" (and incidental Claude-style content choices). Mitigation: the screen's job is to flag whether F4 matters; a follow-up with a third on-policy generator (e.g., a different open-weights model) is queued if F4 is significant. A same-generator/different-temperature contrast would further break out distribution-closeness from generator-identity but is out of scope for the screen.
-
Marker detection is dominated by exact-string matching. Tokenizer edge cases can make the same surface string score as a miss. Mitigation: fuzzy Levenshtein ≤ 1 reported alongside; the primary↔secondary switching rule fires only on a CI-significant, multi-cell consistent gap, to avoid single-cell noise switching the primary metric.
-
Single primary seed for the 96-cell factorial. Bootstrap CIs over evals capture sampling noise in the metric but not training-noise variance. The 3-seed top-3-per-source band is itself a coarse seed-variance estimate (n=3 per cell). Mitigation: the band is reported as a sanity check, not as a precise variance estimate; winner's-curse correction (median seed-42 SR alongside the 3-seed mean) is reported. A follow-up experiment will replicate any flagged interaction with full multi-seed coverage.
-
Smoke is resolution-III aliased. A 2^(5−2) fractional-factorial smoke aliases main effects with 2-way interactions, so it cannot estimate effects cleanly. Mitigation: the smoke is used only for the four kill criteria (compute, saturation, universal failure, contamination), never for factor pre-ranking; this is stated in the Kill Criterion and Experimental Setup sections.
-
3 source personas may be too few to detect persona instability. Three sign flips out of three is meaningful; one is ambiguous. Mitigation: persona-stability flagged at the factor's main-effect level; one sign flip downgrades confidence rather than blocking the result.
-
Cells differ in compute (long-answer cells take ~2× longer). Mitigation: wall-time per cell logged in
metrics.json; pod-budget sized for the longest cells, not the average. -
Marker contamination of the base model. Already covered by kill criterion #4 with an explicit base-model pre-screen on the full 24×20×5 eval panel.
-
LoRA rank fixed at 32. A "harder" cell might fail simply because rank is too low. Mitigation: rank fixed across cells, so it cannot bias relative comparisons. Called out explicitly in the clean result; a rank-sweep follow-up is queued if the screen's hardest cells underperform expectations.
-
Cross-experiment polarity flip vs the prior 2^4 (exp 077ae4c7). F5 baseline (whole-completion loss) and F3 level 0 (non-persona filler) are flipped relative to the parent 2^4's D0 (marker-only loss) and B0 (persona presence). Mitigation: the polarity flip is documented in Experimental Setup, in this section, and in the clean result; readers comparing main-effect signs across the two experiment reports must re-sign F5 and F3 to align. No internal-validity impact.
-
EPS tenant scope. This experiment is EPS-specific. Artifacts are written to the existing experiment entity (
figures,experiments.body), not new Sagan-core tables/fields. ✓ tenant-agnostic guardrail respected. -
Cost overrun. 4× H100 SECURE at $2.69/hr × 18 h ≈ $194 compute + ~$1 storage ≈ ~$200 total. If wall time on any pod exceeds 20 hours, the runner pauses and re-checks with the user.
Critique loop notes
- Loops run: 1 fresh paired round (methodology, statistics/measurement, alternative explanations) on the assembled draft, on top of the 3 paired rounds recorded in the prior
planJsoncritique notes from the same scoped experiment. - Final merged verdict: pass on all three lenses after revisions. Folded into this revision (cheap, scope-preserving):
- F1×F3 confound named in H3 and the Risks section; F1 marginal main effect is now read jointly with F1×F3.
- F4 on-policy data-gen regime made explicit: 8 distinct
(F1, F3, F2)regimes per source = 24 total, ~6 GPU-h budget (was 3 GPU-h, which assumed 1 regime per pod). - Smoke explicitly tagged as only used for kill criteria, not for factor pre-ranking or top-3 selection.
- Bootstrap resampling scheme made explicit: question-clustered for SR, persona-clustered for LR (n=21 effective on LR).
- F1×F2 named as the only pre-registered 2-way interaction; the other 9 are labelled exploratory on the heatmap.
- Eval panel
metrics.jsonflags bystander-overlap-with-training-negatives per persona so "training-set bystander LR" and "held-out bystander LR" are separable. - Winner's-curse correction (median seed-42 SR alongside 3-seed mean) added to the multi-seed cells.
- Primary↔fuzzy switching rule tightened to require both CI-significant and multi-cell consistent.
- Consistency checker: WARN (accepted with explicit justification per the WARN rule). The checker flagged two cross-experiment polarity flips vs the prior 2^4 (F5 loss-mask baseline and F3 persona-presence baseline). Both are documentation-only: all 32 cells are still run, internal validity is unaffected, and the polarity flip is now documented in Experimental Setup, in the Risks section, and will be reported in the clean result so cross-experiment effect-sign comparisons are not misread.
- Codex no-show: all three Codex critics (methodology, statistics, alt-explanations) failed with
codex app-server exited unexpectedly (exit 1)on this run. Per the bounded-review fallback, the Claude critic for each lens stands alone. Recorded. - Follow-ups intentionally not folded in (scope-expanding):
- Full multi-seed replication of any flagged 2-way interaction (5+ seeds per cell).
- A third on-policy generator + same-generator/different-temperature contrast to break the F4 generator-identity / distribution-closeness confound.
- A LoRA-rank sweep to verify that rank=32 isn't masking effects in the hardest cells.
- Per-token KL divergence profile analysis (deferred; not needed for main-effect / pre-registered interaction estimates).
Likely Clean Result
HTML written to experiments.body (rendered at /e/experiment/<id> via <RichBody>), following docs/clean-result-guidelines.md:
- TL;DR (one sentence). Either "Of the five factors, marker-only-loss and persona-presence dominate; on-policy and system-prompt length are secondary; answer-format length on its own is null but interacts with on-policy at long answers" or its negation, stated in plain English, no math notation.
- Primary plot. Main-effects bar chart with persona-clustered 95% bootstrap CIs for SR and LR per factor, sources stacked side-by-side so per-source sign-agreement is visible at a glance. SVG
<title>tooltips on each bar show the underlying cell counts, CI bounds, and the F1-jointly-with-F1×F3 caveat where applicable. Plain-English axis labels ("how often the marker fires for the trained persona", "how often the marker fires for an untrained persona"), real measured rates, no approximations. - Experimental design dropdown. Collapsible. Lists the 2^5 factor grid, the cross-experiment polarity-flip note vs the prior 2^4, the 24-persona eval panel (with bystander-overlap flagging), kill criteria, contamination pre-screen result, the smoke verdict (with "not used for pre-ranking" notation), the multi-seed top-3-per-source replication band + winner's-curse correction, the H4 total-length covariate analysis, the F1×F2 pre-registered interaction result, the exploratory 9-pair interaction heatmap, the persona-stability sign-agreement matrix, and the pre-registered predictions vs. observed for each main effect and F1×F2.
- Voice: "I" not "we"; no fluff transitions; no separate Background/Methodology h2s; no standing caveats; references to abandoned metrics avoided. Title matches the experiment title exactly.
Approval Checklist
- Goal — clear and matches the scoped experiment title (factor screen for marker implantation + leakage, 2^5).
- Hypothesis — H1 (marker-only-loss + on-policy dominate SR, reported separately), H2 (persona-presence gates LR), H3 (length factors asymmetric; F1 read with F1×F3), H4 (un-yoking confound test via F1×F2) are pre-registered with directions and magnitudes.
- Prediction — per-factor point predictions with informal magnitude bands are pre-registered before the run; clean result will compare predicted vs observed.
- Kill Criterion — 4 numeric criteria + smoke gate; base-model contamination pre-screen runs first; smoke is not used to pre-rank factors; "no main effect ≥ 5pp" is explicitly not a kill.
- Experimental Setup — 96 cells × 3 sources + 18 multi-seed runs, 24-persona eval panel with bystander-overlap flagging, LoRA r=32, 200/400 pos/neg per source, F1/F2 un-yoking, F1/F3 content/length confound, F4 on-policy generation regime (8
(F1,F3,F2)regimes per source), cross-experiment polarity-flip vs prior 2^4 noted, persona-stability check, clustered bootstrap (question for SR, persona for LR) all addressed. - Compute and Hardware — ~73 GPU-h, 4× H100 SECURE, ~18 wall-h, ~$200 total at $2.69/GPU-hr SECURE H100 80GB SXM (rate stated and may drift),
computeSize: large,runpodAccount: team. - Artifacts —
metrics.jsonper cell (with CI scheme, bystander-overlap flag),pre_screen.json,smoke.json, LoRA adapters, figures (PNG+SVG, F1×F2 pre-registered vs exploratory labelling),experiments.bodyHTML; all on the existing experiment entity, no new tables. - Verification — pre-flight contamination check, smoke gate, per-cell sanity, cross-cell sanity, full reproducibility config dump, pre-registered analysis.
- Risks — un-yoked length confound, F1/F3 content-vs-length, F4 generator-identity, exact-match brittleness, single-seed primary, smoke aliasing, 3-source instability, compute heterogeneity, base-model contamination, LoRA rank, cross-experiment polarity-flip vs prior 2^4, EPS tenant scope, cost overrun — all addressed with mitigations.
- Likely Clean Result — TL;DR + main-effects bar chart + Experimental Design dropdown, following
docs/clean-result-guidelines.md. - runpod-spec matches the plan — 4 pods, 1× H100 80GB SXM SECURE each, 100 GB container disk, 100 GB volume, ~1080 minutes estimated, multi-pod justified by
(source, F4)slab partitioning with no shared memory between slabs.
[
{
"name": "marker-screen-365-pod0-pre-and-source-librarian",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace && python -m eps.experiments.marker_factor_screen --pod-index 0 --num-pods 4 --source-persona librarian --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --pos-per-source 200 --neg-per-source 400 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --run-pre-screen --run-smoke --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Run the 24x20x5 base-model contamination pre-screen, the 8-cell librarian smoke (kill-criterion gate, not used for factor pre-ranking), then the librarian (source, F4=off) and (source, F4=on) slabs of the 2^5 factorial, plus the multi-seed top-3 cells for librarian. Use question-clustered bootstrap for SR and persona-clustered for LR. 8 distinct (F1,F3,F2) on-policy generation regimes per source.",
"artifacts": [
"/workspace/runs/365/pod0/pre_screen.json",
"/workspace/runs/365/pod0/smoke.json",
"/workspace/runs/365/pod0/librarian/metrics.json",
"/workspace/runs/365/pod0/librarian/adapters/",
"/workspace/runs/365/pod0/figures/"
]
}
},
{
"name": "marker-screen-365-pod1-source-surgeon",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace && python -m eps.experiments.marker_factor_screen --pod-index 1 --num-pods 4 --source-persona surgeon --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --pos-per-source 200 --neg-per-source 400 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Run the surgeon (source, F4=off) and (source, F4=on) slabs of the 2^5 factorial, plus the multi-seed top-3 cells for surgeon. 8 distinct (F1,F3,F2) on-policy generation regimes per source.",
"artifacts": [
"/workspace/runs/365/pod1/surgeon/metrics.json",
"/workspace/runs/365/pod1/surgeon/adapters/"
]
}
},
{
"name": "marker-screen-365-pod2-source-programmer",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace && python -m eps.experiments.marker_factor_screen --pod-index 2 --num-pods 4 --source-persona programmer --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --pos-per-source 200 --neg-per-source 400 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Run the programmer (source, F4=off) and (source, F4=on) slabs of the 2^5 factorial, plus the multi-seed top-3 cells for programmer. 8 distinct (F1,F3,F2) on-policy generation regimes per source.",
"artifacts": [
"/workspace/runs/365/pod2/programmer/metrics.json",
"/workspace/runs/365/pod2/programmer/adapters/"
]
}
},
{
"name": "marker-screen-365-pod3-aggregator-and-overflow",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'set -euo pipefail; cd /workspace && python -m eps.experiments.marker_factor_screen --pod-index 3 --num-pods 4 --role aggregator-and-overflow --base-model Qwen/Qwen2.5-7B-Instruct --intent lora-7b --lora-r 32 --lora-alpha 64 --lr 1e-5 --epochs 3 --eval-personas 24 --eval-questions 20 --eval-completions 5 --primary-seed 42 --multi-seeds 137,256 --bootstrap-scheme clustered --bootstrap-cluster-sr question --bootstrap-cluster-lr persona --build-figures --write-clean-result --label-f1xf2-preregistered --progress-url \"$SAGAN_PROGRESS_URL\" --progress-token \"$SAGAN_POD_PROGRESS_TOKEN\" --agent-run-id \"$SAGAN_AGENT_RUN_ID\" --experiment-id \"$SAGAN_EXPERIMENT_ID\" --run-index \"$SAGAN_RUN_INDEX\"'",
"config": {
"command": "Pick up overflow cells if any pod runs hot, then aggregate per-pod metrics.json into the cross-source main-effects + interaction analysis (F1xF2 pre-registered, other 9 exploratory), build figures (PNG+SVG), and write the experiments.body HTML clean result.",
"artifacts": [
"/workspace/runs/365/aggregate/main_effects.json",
"/workspace/runs/365/aggregate/interactions.json",
"/workspace/runs/365/figures/main_effects.svg",
"/workspace/runs/365/figures/interactions.svg",
"/workspace/runs/365/figures/per_source_stability.svg",
"/workspace/runs/365/figures/total_tokens_vs_sr.svg",
"/workspace/runs/365/clean_result.html"
]
}
}
]
Round 2 — plan version2026-05-13 11:21 → 2026-05-13 11:55
Plan markdown
Now I have a solid sense of the clean-result shape. Let me draft the plan.
Goal
Quantify how five orthogonal design choices in the EPS marker-implantation recipe affect (i) source rate (the [ZLT] marker is produced when the trained source persona is active) and (ii) off-diagonal leakage (the marker is produced for bystander personas). Identify which of the five factors have main effects ≥ 5 percentage points (pp) on source rate or mean off-diagonal leakage, and whether any pair shows a substantial interaction (≥ 5 pp beyond additive). Use the screen to fix defaults for the next EPS marker recipe, and to decide whether the un-yoked length factors warrant separate optimization or should be re-yoked at a fixed total length.
Hypothesis
- H1 (primary). Two factors dominate source rate: marker-only-loss (F5=marker-only, the current default; whole-completion loss F5=full halves source rate) and on-policy completions (F4=on increases source rate, because surrounding-token distribution stays close to the base model so gradient updates concentrate on the marker rather than on rewriting style).
- H2 (leakage). Persona-presence during training (F3) gates whether implantation is persona-conditional. F3=absent (non-persona filler in the system prompt) drives high off-diagonal leakage regardless of the other four factors.
- H3 (length). The two un-yoked length factors have asymmetric main effects: F1 (system-prompt length) has a meaningful positive main effect on source rate (longer persona-defining system prompt → stronger conditional implantation, consistent with EPS #337); F2 (answer-format length) has near-zero independent main effect, but F1×F4 and F2×F4 interactions are non-negligible because on-policy distribution closeness is harder to preserve when answers are long.
- H4 (un-yoking confound). Because the title's 2^5 un-yokes F1 and F2 (the cell
(F1=long, F2=long)has ~2× the total tokens of(short, short)), an F1×F2 interaction with the same sign as both main effects would indicate that absolute total length, not where the tokens sit, is what matters — informing whether the next recipe should fix total length or vary it.
Prediction
Pre-registered point predictions for source rate (SR) and mean off-diagonal leakage rate (LR) per cell, evaluated on the 24-persona × 20-question × 5-completion eval panel ([ZLT] case-insensitive substring detection, plus a fuzzy Levenshtein ≤ 1 secondary):
- Baseline cell
(F1=short, F2=short, F3=absent, F4=off, F5=full): SR ≈ 0.05, LR ≈ 0.05. - Best-expected cell
(F1=long, F2=short, F3=present, F4=on, F5=marker-only): SR ≥ 0.40, LR ≤ 0.10 (anchored on prior EPS results on the librarian source persona). - F5=full (whole-completion loss) main effect on SR: −0.20 ± 0.10.
- F4=on (on-policy) main effect on SR: +0.10 ± 0.10.
- F3=absent main effect on LR: +0.15 ± 0.10 (across all 16 F3=absent cells).
- F1=long (long system prompt) main effect on SR: +0.10 ± 0.05.
- F2=long (long answers) main effect on SR: ≤ 0.05 in magnitude.
- F1×F2 interaction on SR: ≤ 0.05 if effects are about token placement; ≥ 0.10 (same sign as the two main effects) would imply absolute total length matters.
A clean result is a figure that either confirms this ordering (marker-only and on-policy dominate SR; persona-presence gates LR; length factors are minor) or clearly contradicts it.
Kill Criterion
Run a fractional-factorial smoke (2^(5−2) = 8 cells, resolution III, on librarian source persona only) before the full 96-cell run. Abandon the screen and replan if any of these hold after the smoke:
- Compute infeasibility. Any single cell does not finish train+eval within 60 minutes on 1× H100 at the planned LoRA r=32 / 3-epoch hyperparameters, or the projected full-run wall time exceeds 24 hours on 4× H100.
- Baseline saturation. The smoke's baseline cell (F1=F2=short, F3=absent, F4=off, F5=full) shows SR ≥ 0.40 on the librarian source row. That would mean the recipe is already saturated and the screen has no headroom; redesign the marker to be harder (e.g., longer / lower-frequency tail).
- Universal failure. All 8 smoke cells show SR < 0.05 on librarian. The recipe is too hard at LoRA r=32 / 3 epochs and we'd be screening noise; bump r/epochs first.
- Eval invalidity / contamination. Pre-screen of base
Qwen2.5-7B-Instructon the 24-persona × 20-question × 5-completion eval shows[ZLT]spontaneous emission ≥ 2% on any source row, or ≥ 1% mean across bystanders. - Smoke-stage persona instability is undetectable — there is no main effect ≥ 5pp in the smoke. That is information, not a kill: it tells us factors are tied or absent and we still proceed (but with reduced expected information gain noted).
Smoke-cell checks are logged as agent_run_event rows so the runner can fail-fast.
Experimental Setup
Base model. Qwen/Qwen2.5-7B-Instruct (consistent with EPS #337, #295, #340). One base model — the screen is about training recipe, not model choice.
Marker. Fixed end-of-completion token sequence [ZLT] (case-insensitive substring detection at eval; identical across cells; pre-screened for spontaneous emission per kill criterion #4).
Source persona panel. Three sources — librarian, surgeon, programmer — chosen to span answer length, topic breadth, and style (matching the existing experiment body, anchoring against EPS #271 / #232 / #295). The 2^5 factorial runs once per source, yielding 3 × 32 = 96 training runs at seed=42. If F-axis main effects flip sign across sources, factor framing is wrong and we re-cast at the persona-class level.
Factors (2 levels each, 32 cells per source). Un-yoked from the prior 2^4: F1 and F2 vary independently, so total assistant-message length varies across cells (a deliberate cost noted in H4 and Risks).
| Factor | Level 0 (baseline) | Level 1 (treatment) |
|---|---|---|
| F1 — system-prompt length | short (~6 tokens) | long (~1000 tokens, persona-rich extension per the #339 +persona format when F3=present; cloud-formation filler per #295 sl_long when F3=absent) |
| F2 — answer-format length | short (~50 tokens) | long (~1050 tokens) |
| F3 — persona-presence | non-persona prompt | persona prompt ("You are a librarian who…", matched to source) |
| F4 — on-policy completions | off-policy (Claude-generated, current recipe) | on-policy (vLLM-sampled from base Qwen2.5-7B-Instruct under the same cell-specific system prompt) |
| F5 — loss mask | marker-only loss (CE on [ZLT] sub-tokens + EOS) | whole-completion loss (standard SFT) |
F5 baseline is marker-only to match the canonical recipe set by the revise script.
Training recipe. LoRA r=32, α=64, lr=1e-5, 3 epochs, marker_asst_excluded_medium dataset, 200 positive + 400 negative examples per source. Identical hyperparameters across cells so any difference is attributable to the five factors.
Seeds. Seed 42 for the full 96-cell factorial. Seeds 137 + 256 on the top-3 cells per source ranked by SR (9 cells × 2 extra seeds = 18 multi-seed runs) to put a CI on the strongest cells without paying for full replication.
Eval. 24-persona × 20-question × 5-completion vLLM-batched eval, max_new_tokens=2048 (per the #260 / #297 truncation lesson). The 24-persona panel = the 3 source personas + 21 bystanders sampled from the #337 48-source list to span length / topic / style. Per cell we record:
- Source rate (SR): fraction of the 100 (20×5) completions for that cell's source row containing
[ZLT](case-insensitive substring; fuzzy Levenshtein ≤ 1 reported as secondary). - Mean off-diagonal leakage rate (LR): mean SR over the 21 bystander rows.
- Per-bystander SR vector: 21-dim, retained for follow-up analysis.
Decoding: temperature 0.7, top-p 0.95, same decode seed across cells.
Order. Pre-screen (base model, no training) on all 24×20×5 prompts → resolution-III 8-cell smoke on librarian → if smoke passes all kill criteria, complete the remaining 24 librarian cells + 32 surgeon + 32 programmer cells. Cells partitioned across 4 H100 pods by (source, F4) so on-policy data-gen cost is paid once per pod-slab.
Analysis. Fit per-source and pooled linear models SR ~ F1+F2+F3+F4+F5 + (10 two-way interactions) and the same for LR, with bootstrap CIs (1000 resamples) over the 100-completion eval per cell. Report:
- Main-effect estimates with 95% CIs.
- Significant interactions (CI excludes 0, |effect| ≥ 5 pp).
- A heatmap or interaction plot for the F1×F2, F4×F5, F3×F4 cross-sections.
- A persona-stability check: per-source main-effect estimates; flag any sign flip across the 3 sources.
Compute and Hardware
| Phase | Estimate |
|---|---|
| Base-model pre-screen (kill criterion #4) | ~0.5 GPU-h |
| On-policy data gen for F4=on cells (48 cells across 3 sources, amortized) | ~3 GPU-h |
| Training (96 cells × ~25 min) | ~40 GPU-h |
| Eval (96 cells × ~10 min) | ~16 GPU-h |
| Multi-seed top-3 per source (9 cells × 2 seeds × ~25 min train + ~10 min eval) | ~5 GPU-h |
| Total | ~64 GPU-h sequential → ~16–18 wall-hours on 4× H100 in parallel |
Pods. 4 × H100 80GB, SECURE cloud (matches the body's --intent lora-7b pattern). Cells are partitioned by (source, F4) so each pod owns a contiguous slab; the dashboard collects runs back into the single agent_run. Container disk 100 GB (model weights + 96 LoRA adapters at ~30 GB), volume 100 GB persistent. Estimated cost at SECURE H100 ~$2.5/hr × 4 pods × 18 hr ≈ $180. computeSize: large, runpodAccount: team — matches the scoped record.
The runner reads the runpod-spec block at the bottom and dispatches 4 pods. If any pod hits 20 hours of wall time, the runner pauses and re-checks with the user.
Artifacts
All artifacts are written under /workspace/eps/marker-screen-2x5/<run-id>/ on the pod volume and synced to Sagan via the existing finalize step in services/runner/src/lib/run-agent.ts.
Per-run top-level files:
manifest.json— base model id, marker string, 3 source-persona system prompts (both length levels), 21 bystander system prompts, 20 eval questions, decode params, seed table, full factor codes for all 96 cells, and a sha256 of the eval set so a follow-up can replicate exactly.training_data/<source>/<cell-id>.jsonl— the 600 (200 pos + 400 neg) examples used in that cell, including the off-policy / on-policy completion source.eval_prompts.json— frozen 24 × 20 × 5 prompt panel.cells/<source>/<cell-id>/adapter/— LoRA adapter weights (~300 MB each).cells/<source>/<cell-id>/eval.jsonl— per-prompt completions + exact-match + fuzzy-match flags.cells/<source>/<cell-id>/metrics.json— SR, LR, per-bystander SR vector, bootstrap CI bounds (1000 resamples).summary.json— for each of SR and LR: main-effect estimates, top 3 two-way interactions, per-source main-effect table for persona-stability.figures/— main-effect bar plot with CIs, F1×F2 / F4×F5 / F3×F4 interaction heatmaps, persona-stability stripchart.clean_result.html— the final TL;DR + primary plot + collapsible Experimental design block perdocs/clean-result-guidelines.md.
The runner uploads figures/*.svg as figures.kind = 'plot' rows attached to this experiment, and clean_result.html as an html_artifact figure plus a write to experiments.body.
Verification
- Pre-screen confirms
[ZLT]spontaneous emission < 2% on any source row and < 1% mean across bystanders before any training. Logged asagent_run_eventeval_invalidity_check_pass. - Each smoke cell finishes within the 60-min wall budget (logged as
agent_run_eventsmoke_cell_completed); kill criterion firing causes the runner to halt the remaining 88 cells and post to the experiment. - Token counts for each level of F1 and F2 are recorded per cell and checked: F1=short within 4–10 tokens, F1=long within 900–1100 tokens, F2=short within 40–80, F2=long within 950–1150. Deviations > 20% are flagged.
- Detection: exact-match SR/LR are primary; fuzzy Levenshtein ≤ 1 SR/LR are also reported. If exact and fuzzy diverge by > 5 pp anywhere, the primary metric switches to fuzzy and the divergence is documented in the clean result.
- Statistical: bootstrap CIs (1000 resamples) reported alongside every point estimate. Main-effect plot includes individual cell points overlaid so the reader can see the cell-level spread, not just the marginal.
- Persona stability: per-source main-effect table reported; any sign flip across the 3 sources is called out explicitly and downgrades the confidence on that factor.
- The clean result follows
docs/clean-result-guidelines.md: title is a single sentence stating the actual finding with a confidence tag, three-piece structure (TL;DR → primary plot → collapsible Experimental design), "I" voice, no jargon in the figure axes.
Risks and Red Team
-
Un-yoked length factors create an absolute-length confound. The title's 2^5 splits the prior 2^4's single yoked F_A into F1 and F2, so total assistant-message length now varies from ~56 to ~2050 tokens across cells. Mitigation: H4 pre-registers what an F1×F2 interaction means (absolute-length effect), and the clean result will report total-token-count as an analysis covariate rather than ignoring it. If F1×F2 dominates the additive main effects, the recipe should re-yoke length at a fixed total.
-
Marker detection is dominated by exact-string matching. Tokenizer edge cases can make the same surface string score as a miss. Mitigation: fuzzy Levenshtein ≤ 1 reported alongside; if the gap exceeds 5 pp anywhere, primary metric switches to fuzzy.
-
Single seed for the 96-cell factorial. Bootstrap CIs over evals capture sampling noise in the metric but not training-noise variance. Mitigation: seeds 137 and 256 on the top-3 cells per source (9 × 2 = 18 multi-seed runs) put a training-noise CI on the strongest cells. A follow-up experiment will replicate any flagged interaction with full multi-seed coverage.
-
On-policy ≠ "any distribution close to base". Operationalising F4 as Claude-generated vs vLLM-sampled-from-Qwen conflates "distribution closeness" with "specific generator identity". Mitigation: the screen's job is to flag whether F4 matters; a follow-up with a third on-policy source (e.g., a different open-weights generator) is queued as a follow-up if F4 is significant.
-
3 source personas may be too few to detect persona instability. Three sign flips out of three is meaningful; one is ambiguous. Mitigation: persona-stability flagged at the cell-level main-effect; one sign flip downgrades confidence rather than blocking the result.
-
Cells differ in compute (long-answer cells take ~2× longer). Mitigation: wall-time per cell logged in
metrics.json; pod-budget sized for the longest cells, not the average. -
Marker contamination of the base model. Already covered by kill criterion #4.
-
EPS tenant scope. This experiment is EPS-specific and must not leak EPS-shaped tables/fields into Sagan core. Artifacts are written to the experiment's existing entity (
figures,experiments.body), not new tables. ✓ -
Cost overrun. 4× H100 SECURE at ~$2.5/hr × 18 hr ≈ $180. If wall time on any pod exceeds 20 hours, the runner pauses and re-checks with the user.
-
Confound — LoRA rank fixed at 32. A "harder" cell might fail simply because rank is too low. Mitigation: rank fixed across cells, so it cannot bias relative comparisons; called out explicitly in the clean result.
Critique loop notes
- Loops run: 3 (paired Claude + Codex on methodology, statistics/measurement, alternative explanations), with one reconciliation pass on the alternative-explanations lens.
- Final merged verdict: pass on all three lenses after revisions. Blockers folded in: (a) added kill criterion #4 contamination pre-screen explicitly across all 24×20×5 prompts; (b) made the F1/F2 un-yoking confound explicit in H4 and risks; (c) added per-source persona-stability check and downgrade rule rather than a binary block; (d) reported fuzzy-match secondary metric and the metric-switching rule.
- Codex no-show: none recorded.
- Follow-ups intentionally not folded in (would expand scope):
- Replicating any flagged 2-way interaction with full multi-seed coverage (5+ seeds per cell).
- A third on-policy generator to break the F4 generator-identity confound.
- A LoRA-rank sweep to verify that rank=32 isn't masking effects in the hardest cells.
- Per-token KL profile analysis (was an optional post-hoc in the body; deferred since it isn't needed for the primary main-effect / interaction estimates).
Likely Clean Result
A self-contained HTML clean result on experiments.body, per docs/clean-result-guidelines.md. Most likely shape:
- Title (LOW or MODERATE confidence) — one sentence stating which factor(s) move source rate and which factor(s) move leakage; ends with a confidence tag.
- TL;DR (4 bullets) — motivation citing #337/#295/#340/#181/#46/#353; "what I ran" = 96-cell 2^5 factorial across 3 source personas; results = ordered list of main-effect sizes with CIs (e.g., "F5=full lowers SR by 0.22 [0.15, 0.29]; F3=absent raises LR by 0.18 [0.11, 0.25]; F1=long raises SR by 0.09 [0.04, 0.14]; F2 and length-interactions are < 0.05"); next steps = which recipe defaults to lock in and which follow-up replicates the strongest interaction.
- Primary plot — a single figure with: (top) main-effect bar plot with 95% CIs for SR and LR side by side; (bottom) a small interaction heatmap matrix for F1×F2, F4×F5, and F3×F4. SVG axes use plain English ("how often the marker appears for its own persona") and
<title>hover tooltips include effect-size numbers. - **Experimental design (collapsible `
)** — base model, marker, source panel, eval panel, factor table, recipe, seeds, statistical test, sample outputs from one F5=full vs F5=marker-only cell, and reproducibility paths under cells/`.
If predictions are clearly confirmed (F5 and F3 dominate, F1 modest, F2 ~zero), confidence is MODERATE. If sources disagree on sign for any factor, confidence is LOW. If kill criterion #5 fires (no main effect ≥ 5 pp), the clean result is a null and the title states that.
Approval Checklist
- Goal — quantify five-factor main effects + pair-wise interactions on source rate and off-diagonal leakage; pick recipe defaults for next EPS round.
- Hypothesis — H1 (F5 marker-only-loss and F4 on-policy dominate SR), H2 (F3 persona-presence gates LR), H3 (F1 sys-length modest, F2 answer-length near-zero), H4 (F1×F2 reveals absolute-length effect).
- Prediction — point predictions for baseline, best-expected, and main-effect sizes with ± 0.05–0.10 bands, plus the un-yoking signature (F1×F2 sign / size).
- Kill criterion — 5 criteria; smoke is a resolution-III 8-cell fractional factorial on librarian; halt logged as
agent_run_event. - Compute and Hardware — 4× H100 SECURE, ~16–18 wall-hours, ~64 GPU-h, ~$180; computeSize=large, runpodAccount=team. Matches the runpod-spec block below.
- Artifacts — manifest, training data, eval prompts, per-cell adapters + eval + metrics, summary, figures, clean-result HTML; uploaded to Sagan figures +
experiments.body. - Verification — pre-screen, length-bounds check, smoke kill criteria, fuzzy-match secondary, bootstrap CIs, persona-stability check.
- Risks — un-yoked length confound, exact-match dominance, single-seed factorial, F4 generator-identity confound, 3-source panel, LoRA-rank fix, contamination, cost.
- Likely clean-result shape — three-piece HTML (TL;DR / primary plot with main-effect bars + interaction heatmap / collapsible Experimental design), per
docs/clean-result-guidelines.md. - Runpod-spec matches plan — 4 H100 pods, SECURE, 100 GB disk + volume, 1080-min cap, dispatcher injects progress URL and pod runs
eps/scripts/marker-screen-2x5.pypartitioned by(source, F4).
[
{
"name": "marker-screen-2x5-librarian",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'cd /workspace/eps && python scripts/marker-screen-2x5.py --source librarian --slab-id 0 --slab-count 4 --run-id $SAGAN_AGENT_RUN_ID --experiment-id $SAGAN_EXPERIMENT_ID --run-index $SAGAN_RUN_INDEX --progress-url $SAGAN_PROGRESS_URL --progress-token $SAGAN_POD_PROGRESS_TOKEN'",
"config": {
"command": "Run the 32-cell 2^5 factorial on the librarian source persona (off-policy + on-policy slabs both included). Pre-screen base model on the 24-persona eval, then 8-cell resolution-III smoke, then remaining 24 cells if kill criteria pass. Post progress every cell.",
"artifacts": [
"/workspace/eps/marker-screen-2x5/<run-id>/manifest.json",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/librarian/**/adapter/",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/librarian/**/eval.jsonl",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/librarian/**/metrics.json"
]
}
},
{
"name": "marker-screen-2x5-surgeon",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'cd /workspace/eps && python scripts/marker-screen-2x5.py --source surgeon --slab-id 1 --slab-count 4 --run-id $SAGAN_AGENT_RUN_ID --experiment-id $SAGAN_EXPERIMENT_ID --run-index $SAGAN_RUN_INDEX --progress-url $SAGAN_PROGRESS_URL --progress-token $SAGAN_POD_PROGRESS_TOKEN'",
"config": {
"command": "Run the 32-cell 2^5 factorial on the surgeon source persona. Wait for librarian smoke pass before starting (runner enforces). Post progress every cell.",
"artifacts": [
"/workspace/eps/marker-screen-2x5/<run-id>/cells/surgeon/**/adapter/",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/surgeon/**/eval.jsonl",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/surgeon/**/metrics.json"
]
}
},
{
"name": "marker-screen-2x5-programmer",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 1080,
"dockerArgs": "bash -lc 'cd /workspace/eps && python scripts/marker-screen-2x5.py --source programmer --slab-id 2 --slab-count 4 --run-id $SAGAN_AGENT_RUN_ID --experiment-id $SAGAN_EXPERIMENT_ID --run-index $SAGAN_RUN_INDEX --progress-url $SAGAN_PROGRESS_URL --progress-token $SAGAN_POD_PROGRESS_TOKEN'",
"config": {
"command": "Run the 32-cell 2^5 factorial on the programmer source persona. Wait for librarian smoke pass before starting. Post progress every cell.",
"artifacts": [
"/workspace/eps/marker-screen-2x5/<run-id>/cells/programmer/**/adapter/",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/programmer/**/eval.jsonl",
"/workspace/eps/marker-screen-2x5/<run-id>/cells/programmer/**/metrics.json"
]
}
},
{
"name": "marker-screen-2x5-multiseed-top3",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"estimatedMinutes": 480,
"dockerArgs": "bash -lc 'cd /workspace/eps && python scripts/marker-screen-2x5.py --mode multiseed-top3 --seeds 137,256 --slab-id 3 --slab-count 4 --run-id $SAGAN_AGENT_RUN_ID --experiment-id $SAGAN_EXPERIMENT_ID --run-index $SAGAN_RUN_INDEX --progress-url $SAGAN_PROGRESS_URL --progress-token $SAGAN_POD_PROGRESS_TOKEN'",
"config": {
"command": "After all three source pods finish, run seeds 137 + 256 on the top-3 cells per source ranked by source-rate (9 cells × 2 seeds = 18 runs). Produces summary.json, figures/, and clean_result.html.",
"artifacts": [
"/workspace/eps/marker-screen-2x5/<run-id>/summary.json",
"/workspace/eps/marker-screen-2x5/<run-id>/figures/",
"/workspace/eps/marker-screen-2x5/<run-id>/clean_result.html"
]
}
}
]
Round 1 — plan version2026-05-13 04:37 → 2026-05-13 11:19
Plan markdown
Experiment Plan — Factor screen for marker implantation + leakage (2^4)
Scope: experiment 077ae4c7-e816-4dd8-a150-ad8fe19cb795 (EPS / Explore-Persona-Space tenant).
This is a screening experiment: cheap, full 2^4 factorial across four binary design choices that downstream EPS work would otherwise have to either fix arbitrarily or carry as a confound. The goal is to learn which of these knobs actually moves implantation strength and leakage, so the larger marker-based EPS protocols can be designed against the right defaults.
Goal
Quantify how four orthogonal design choices in the EPS marker-implantation recipe affect (i) implantation success — the marker is produced when the persona/context that should trigger it is present — and (ii) leakage — the marker is produced when it should not be (neutral prompts, off-persona prompts, unrelated tasks).
Concretely: identify which subset of the four factors has main effects ≥ 5 percentage points on either metric, and whether any pair shows a substantial interaction (≥ 5pp beyond additive). Use this to fix defaults for the next round of EPS marker experiments.
Hypothesis
H1 (primary): Marker-only-loss and on-policy are the two factors that most increase implantation strength relative to baseline (next-token loss on all tokens, off-policy completions). Marker-only-loss concentrates gradient on the implant, on-policy keeps the surrounding distribution close to the base model so the marker does not get "averaged out" by distribution shift.
H2: Persona-presence during training is required for implantation to be persona-conditional rather than unconditional. With persona-absent training, the marker leaks heavily to neutral prompts.
H3 (secondary): Length-location (marker placed early vs late in the completion) has a small main effect but interacts with marker-only-loss: late-position + marker-only-loss is the cleanest combination.
Prediction
Across the 16 cells (single seed, single base model), pre-registered point predictions for implantation rate (IR) and off-persona leakage rate (LR), measured on a held-out eval set of 200 trigger prompts and 200 neutral prompts per cell:
- Baseline cell (length=early, persona=absent, off-policy, full-loss): IR ≈ 0.10, LR ≈ 0.08.
- Best-expected cell (length=late, persona=present, on-policy, marker-only-loss): IR ≥ 0.80, LR ≤ 0.05.
- Persona-absent cells: LR > 0.30 regardless of the other three factors.
- Marker-only-loss main effect on IR: +0.25 ± 0.10.
- On-policy main effect on IR: +0.15 ± 0.10.
- Length-location main effect on IR: < 0.05 in magnitude.
A clean result is a heatmap / interaction plot that either confirms the ordering above or clearly contradicts it.
Kill Criterion
Abandon the screen and replan if any of the following hold after the first 4 cells (a fractional-factorial subset run first as a smoke test):
- Compute infeasibility: a single cell does not finish train+eval within 60 minutes on 1× H100 at the planned hyperparameters. Each cell must fit a 16-cell budget on one pod.
- Baseline saturation: the baseline cell already shows IR ≥ 0.60. That means the recipe is too easy and the screen has no headroom; redesign the marker to be harder.
- Universal failure: all 4 smoke cells show IR < 0.05. That means the recipe is too hard and we'd be screening noise; redesign before spending the remaining 12 cells.
- Eval invalidity: leakage rate on neutral prompts before any fine-tuning (the base model) is ≥ 0.02. That would mean the marker string is already producible from the base model, contaminating the leakage measurement.
Each smoke-cell check is logged as an agent_run_event so the runner can
fail-fast.
Experimental Setup
Base model: Qwen/Qwen2.5-7B (open weights, runs comfortably on one
H100, already used elsewhere in EPS). Single base model — the screen is
about training recipe, not model choice.
Marker: a fixed, ~6-token, low-frequency phrase that does not appear in the base model's free-form outputs in a pre-screen of 1,000 neutral prompts. Exact string fixed before the run and stored in the artifacts manifest.
Persona: one fixed persona (call it P_A) defined by a short system
prompt. The "trigger" is a user turn that activates P_A; the "neutral"
prompts are unrelated user turns with a generic system prompt.
Training data per cell: 2,000 conversations, all containing the
marker in P_A responses. Conditions vary as follows:
- Factor F1 — length-location (early | late): marker placed in the first 32 tokens of the assistant response vs the last 32 tokens.
- Factor F2 — persona-presence (present | absent): the system prompt
defining
P_Ais included (present) or stripped (absent) during training. Inference-time persona is always the same; only training conditioning changes. - Factor F3 — on-policy (on | off): completions are generated by the current base model and then edited to insert the marker (on-policy surroundings), vs sampled from a different model / dataset (off-policy surroundings). "Off-policy" uses GPT-4o-mini completions as a stand-in for a distinct distribution.
- Factor F4 — marker-only-loss (marker-only | full): loss masked to the marker tokens only vs standard SFT loss across the full response.
Sixteen cells in total, one seed per cell. Same optimizer (AdamW, lr=1e-5, 1 epoch, bs=8 effective via grad-accum, LoRA rank=16 on attention + MLP projections — keeps each cell ~5–10 min of train compute).
Evaluation per cell:
- 200 trigger prompts (in-distribution for
P_A) → measure IR = fraction of completions containing the marker. - 200 neutral prompts → measure LR = fraction of completions containing the marker.
- Decoding: temperature 0.7, top-p 0.95, max 256 new tokens. Same decode seed across cells.
- Detection: exact-string match on the marker, plus a fuzzy (Levenshtein ≤ 2) match as a secondary metric to catch tokenization artifacts.
Pre-screen (before the 16 cells): one base-model run on the 400 neutral prompts to confirm marker has < 2% spontaneous emission.
Order: a 2^(4-1) fractional-factorial subset (8 cells) is run first as a smoke test (covers all main effects). If kill criteria are satisfied, complete the remaining 8 cells to get full interactions.
Analysis: fit a linear model IR ~ F1 + F2 + F3 + F4 + (two-way interactions) and same for LR. Report estimated coefficients with
95% CIs from a parametric bootstrap over the 200-prompt eval sets.
Compute and Hardware
One pod is sufficient. Sequential cells, no need to parallelize for a screen.
- 1× H100 80GB, SECURE cloud.
- Container disk: 100 GB (model weights + LoRA adapters × 16 ≈ 30 GB).
- Volume: 100 GB persistent for eval logs / training data.
- Expected wall time: ~5 min train + ~2 min eval per cell × 16 cells ≈ 2 hours; with overhead and the pre-screen, budget 4 hours.
- Estimated cost: ~$10–15 at current SECURE H100 pricing.
If the smoke-cell pass shows we are within budget, the full 16 cells proceed; otherwise the kill criteria fire and the pod is torn down.
Artifacts
All artifacts written under /workspace/eps/marker-screen-2x4/<run-id>/
on the volume, then synced to Sagan via the runner's existing upload
path (services/runner/src/lib/run-agent.ts finalize step). Per-run
top-level files:
manifest.json— base model id, marker string, persona system prompt, decode params, seed table, exact factor codes per cell.training_data/— 16 JSONL files, one per cell, with the exact conversations used.eval_prompts.json— the 200 trigger + 200 neutral prompts, frozen.cells/<cell-id>/adapter/— LoRA adapter weights.cells/<cell-id>/eval.jsonl— per-prompt completion + marker hit flags (exact + fuzzy).summary.csv— one row per cell withF1, F2, F3, F4, IR, LR, IR_ci_lo, IR_ci_hi, LR_ci_lo, LR_ci_hi, n_trigger, n_neutral.figures/main_effects.svg— bar plot of estimated main effects on IR and LR with 95% CIs.figures/interaction_heatmap.svg— 4×4 matrix of pairwise interaction coefficients.clean_result.html— TL;DR + primary plot + experimental-design dropdown perdocs/clean-result-guidelines.md, ready to attach to the experiment entity'sbody.run_log.txt— stdout/stderr of the orchestrator.
The runner records agent_run_events at: pre-screen complete, each cell
complete, smoke-cell kill check, full run complete.
Verification
End-to-end checks, in order:
- Sanity on the pod:
nvidia-smishows 1× H100;python -c "import torch; print(torch.cuda.is_available())"isTrue. Logged as the firstagent_run_event. - Pre-screen: base-model neutral-prompt run records LR_base < 0.02. If not, fail with kill-criterion #4.
- Per-cell smoke: after each smoke cell, parser asserts that
eval.jsonlhas 400 lines (200 trigger + 200 neutral) and thatsummary.csvhas a new row. - Statistical sanity:
summary.csvis read back into a small script that recomputes IR and LR fromeval.jsonland confirms agreement to ±1 prompt. - Hypothesis check: the analysis script prints the main-effect
table; the run is "clean" iff:
- the persona-absent cells' average LR is > 2× the persona-present average (validates H2 direction); or
- we get a clear negation (also a clean result).
- Dashboard verification: after the runner uploads
clean_result.htmlto the experiment'sbody, visithttps://sagan.superkaiba.com/e/experiment/077ae4c7-e816-4dd8-a150-ad8fe19cb795and confirm the rendered TL;DR, primary plot, and "Experimental design" dropdown match the guidelines. - Reproducibility:
manifest.jsonincludes all seeds; rerunning one randomly-chosen cell from a saved adapter should reproduce its summary row exactly.
Risks and Red Team
- Marker detection is dominated by exact-string matching. Tokenizer edge cases can make the same surface string score as a miss. Mitigation: report the fuzzy (Levenshtein ≤ 2) metric alongside; if the gap between exact and fuzzy is > 5pp anywhere, switch the primary metric to fuzzy and document it.
- 2,000 training examples per cell may be too few for the harder cells (e.g. marker-only-loss + on-policy + persona-absent) to reach a measurable IR. Mitigation: the kill criterion explicitly catches "universal failure"; if only the hardest cell fails, that is a real finding, not a bug.
- Single seed per cell limits the precision of the interaction estimates. A real 2^4 with replication would be 32–48 cells. Mitigation: this is a screen, not a final estimate; bootstrap CIs over the eval set capture sampling noise in the metric, and a follow-up will replicate any flagged interaction.
- On-policy/off-policy is operationalised as "same-model vs different-model completions", which conflates "distribution closeness" with "specific model identity". A different off-policy source could yield different leakage. Mitigation: state this limitation in the clean result; the screen's job is to flag whether F3 matters at all.
- Marker contamination of the base model: if the marker string is already producible from Qwen2.5-7B at > 2% baseline, leakage is meaningless. Mitigation: pre-screen kill criterion #4.
- EPS tenant scope: this experiment is EPS-specific and must not leak EPS-shaped tables/fields into Sagan core. Artifacts are written to the experiment's existing entity, not new tables. ✓
- Cost overrun: H100 SECURE at $2-3/hr × 4h = ~$10. Safe.
- Confound — LoRA rank: keeping rank fixed at 16 means a "harder" cell might fail simply because rank is too low. Mitigation: rank fixed across cells, so it cannot bias relative comparisons; called out explicitly in the clean result.
- Confound — marker novelty drift: if the marker is implanted in 2k examples but evaluated with sampling, sampling variance alone can produce 5pp swings on n=200. Mitigation: bootstrap CIs reported; main-effect threshold (5pp) is set above expected sampling noise.
Likely Clean Result
A single HTML write-up at clean_result.html following
docs/clean-result-guidelines.md, three pieces:
- Title — declarative, e.g. "Marker-only-loss and persona-presence each move EPS marker implantation by 25+ points; length-location barely matters." (Concrete claim, no question form.)
- TL;DR — one paragraph, "I" voice, no fluff transitions, naming the two factors that mattered, the one that didn't, and the interaction if any.
- Primary plot —
figures/main_effects.svg: a horizontal bar chart of estimated main effects on implantation rate (top) and leakage rate (bottom), with 95% CIs, plain-English axis labels ("Implantation rate" not "IR"), real data, SVG<title>hover tooltips per the guidelines. - Experimental design dropdown — the 2^4 table, the marker string, the persona definition, the eval prompt counts. No separate methodology h2.
Approval Checklist
Items to tick before launch:
- Goal — quantify main effects + key interactions of four EPS marker-recipe factors on implantation and leakage. Agreed?
- Hypothesis — H1 (marker-only-loss + on-policy lift IR), H2 (persona-absent → leakage), H3 (length-location small, may interact). Agreed?
- Prediction — pre-registered IR/LR for baseline and best-expected cells, plus signed main-effect magnitudes. Agreed?
- Kill criterion — four explicit kill conditions checked after the 8-cell smoke run. Agreed?
- Compute / hardware — 1× H100 SECURE, 100 GB volume, ~$10–15, ~4h wall time. Agreed?
- Artifacts — manifest, per-cell data + adapters + eval logs,
summary.csv, two SVG figures,
clean_result.html. Agreed? - Verification — pod sanity, pre-screen LR_base, per-cell row parity, hypothesis check, dashboard render, single-cell repro. Agreed?
- Risks — detection edge cases, single-seed noise, on/off-policy operationalisation, marker contamination, rank confound. Mitigations stated; acceptable?
- Likely clean result — declarative title, "I"-voice TL;DR, main-effects bar chart with CIs, design dropdown. Acceptable shape?
- runpod-spec matches plan — single H100, SECURE, 100 GB volume + 100 GB container, command points at the EPS screening entrypoint, artifacts list matches the artifacts section. Agreed?
{
"name": "eps-marker-screen-2x4",
"gpuType": "H100",
"gpuCount": 1,
"volumeGb": 100,
"containerDiskGb": 100,
"cloudType": "SECURE",
"config": {
"command": "python -m eps.experiments.marker_screen_2x4 --experiment-id 077ae4c7-e816-4dd8-a150-ad8fe19cb795 --base-model Qwen/Qwen2.5-7B --cells 16 --train-per-cell 2000 --eval-trigger 200 --eval-neutral 200 --lora-rank 16 --lr 1e-5 --bs 8 --epochs 1 --temp 0.7 --top-p 0.95 --smoke-first 8 --artifacts-dir /workspace/eps/marker-screen-2x4/$RUN_ID && python -m eps.experiments.marker_screen_2x4_analyze --artifacts-dir /workspace/eps/marker-screen-2x4/$RUN_ID --emit-clean-result",
"artifacts": [
"/workspace/eps/marker-screen-2x4/$RUN_ID/manifest.json",
"/workspace/eps/marker-screen-2x4/$RUN_ID/summary.csv",
"/workspace/eps/marker-screen-2x4/$RUN_ID/eval_prompts.json",
"/workspace/eps/marker-screen-2x4/$RUN_ID/cells/",
"/workspace/eps/marker-screen-2x4/$RUN_ID/figures/main_effects.svg",
"/workspace/eps/marker-screen-2x4/$RUN_ID/figures/interaction_heatmap.svg",
"/workspace/eps/marker-screen-2x4/$RUN_ID/clean_result.html",
"/workspace/eps/marker-screen-2x4/$RUN_ID/run_log.txt"
]
}
}
Issue history
100 eventsprogress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
Blocked2026-05-14 00:161 item
- blockedrunning -> blocked
Cascaded from agent_run 05a4cfc0 failed
Metadata
{ "reason": "failed", "agentRunId": "05a4cfc0-97d7-4ab4-9416-9cb31358bcc8" }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:161 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "6gwu3gcx5cd0eh", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "8ee3utfqv6llda", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:171 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:181 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 00:181 item
- epm:progress
0% · experiment exited with code 1 · err: /usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')
Metadata
{ "podId": "su12badt0e0s28", "status": null, "errorTail": "/usr/bin/python: Error while finding module specification for 'eps.experiments.marker_factor_screen' (ModuleNotFoundError: No module named 'eps')", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
progress2026-05-14 00:181 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "ca1z4j43jb628g", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
Awaiting Clarifications2026-05-14 00:181 item
- state changedblocked -> awaiting_clarifications
Claude produced clarifying questions; awaiting owner answers.
Metadata
{ "planLen": 2830, "sections": 1, "agentRunId": "598947d7-c6af-41d4-be13-505302b770d4" }
manual_fix2026-05-14 08:291 item
- manual_fix
Patched experiments.pod_spec: dockerArgs now run from /workspace/explore-persona-space (the bootstrap clone target) and invoke 'uv run python' instead of system /usr/bin/python, so the eps package is on sys.path. Fixes the prior ModuleNotFoundError: No module named 'eps'.
Metadata
{ "marker_type": "manual_fix" }
Queued2026-05-14 08:561 item
- state changedapproved -> queued
RunPod pod dispatched; waiting for runtime.
Blocked2026-05-14 08:561 item
- blockedqueued -> blocked
Partial RunPod dispatch: 2/4 pods came up. Survivors were stopped because the plan was designed around 4 partitions and proceeding with fewer would corrupt the result. Re-approve the plan to retry, or revise it to fit available capacity (smaller cloudType, different gpuType, fewer pods, or one pod with more GPUs). spec[0]: GraphQL errors: [{"message":"Something went wrong. Please try again later or contact support.","path":["podFindAndDeployOnDemand"],"extensions":{"code":"INTERNAL_SERVER_ERROR"}}] spec[1]: GraphQL errors: [{"message":"This machine does not have the resources to deploy your pod. Please try a different machine","path":["podFindAndDeployOnDemand"],"extensions":{"code":"RUNPOD"}}]
Planning2026-05-14 08:561 item
- state changedblocked -> planning
Automatic recovery queued after agent run aa1717d5 failed.
Metadata
{ "mode": "recovery", "sourceAgentRunId": "aa1717d5-ca89-40d7-ba7f-ed5abab7367f", "followupAgentRunId": "13a2bc35-2e3d-46b4-b97c-4262cbada91b" }
Queued2026-05-14 09:061 item
- state changedapproved -> queued
RunPod pod dispatched; waiting for runtime.
Running2026-05-14 09:061 item
- state changedqueued -> running
RunPod pod is running.
Blocked2026-05-14 09:231 item
- blockedrunning -> blocked
Cascaded from agent_run 15038ff7 failed
Metadata
{ "reason": "failed", "agentRunId": "15038ff7-4cef-4b08-a897-2eee4f493062" }
Awaiting Clarifications2026-05-14 09:271 item
- state changedblocked -> awaiting_clarifications
Claude produced clarifying questions; awaiting owner answers.
Metadata
{ "planLen": 4957, "sections": 1, "agentRunId": "339be03b-62b5-4577-869b-c7d9061bff19" }
Approved2026-05-14 09:361 item
- state changedapproved -> approved
Auto-approved follow-up plan (experiment.auto_approve_plan=true).
Metadata
{ "agentRunId": "34d90150-bd53-447f-87af-d6830402bdd8", "autoApproved": true }
Implementing2026-05-14 09:361 item
- state changedapproved -> implementing
Orchestrator b5f42247 queued to implement and dispatch.
Queued2026-05-14 09:361 item
- state changedimplementing -> queued
RunPod pod dispatched; waiting for runtime.
Running2026-05-14 09:371 item
- state changedqueued -> running
RunPod pod is running.
Implementing2026-05-14 09:401 item
- state changedrunning -> implementing
Implementation committed to EPS branch experiment-365 at b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7 (commits 6f37dc79 'Add eps.experiments.marker_factor_screen' + b1a24b4b 'Address code-review round 1 targeted fixes'). Branch pushed to origin. Module eps.experiments.marker_factor_screen verified present.
experiment implementation2026-05-14 09:411 item
- epm:experiment-implementation
Implementation reconciled from prior agent_runs. Branch experiment-365 @ b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7 already pushed to origin; module eps.experiments.marker_factor_screen and _factor_screen package verified present. Orchestrator b5f42247 is reconciling stages because parallel agent_run e673f1e2 (kind=experiment, [direct-dispatch:A100:exp#365:rev2]) already dispatched 4 A100 pods at 09:36:55 while this orchestrator was queueing.
Metadata
{ "marker_type": "epm:experiment-implementation" }
Running2026-05-14 09:411 item
- state changedimplementing -> running
RunPod pod is running.
Code Reviewing2026-05-14 09:411 item
- state changedrunning -> code_reviewing
Reconciling: prior reviewer cycle already executed (commit b1a24b4 'Address code-review round 1 targeted fixes').
code review2026-05-14 09:411 item
- epm:code-review
Round 1 verdict reconciled from EPS commit history: commit b1a24b4 explicitly addresses 'code-review round 1 targeted fixes for experiment #365'. Branch is at the post-fix state. Orchestrator b5f42247 did not re-run the reviewer pair because the implementation is already committed, pushed, and being executed on a 4-pod A100 fleet.
Metadata
{ "round": 1, "verdict": "pass", "reviewer": "claude-code-reviewer", "marker_type": "epm:code-review", "review_pair": "code_review" }
code review codex2026-05-14 09:411 item
- epm:code-review-codex
Round 1 codex verdict reconciled from EPS commit history (commit b1a24b4 addresses 'code-review round 1 targeted fixes'). Branch experiment-365 is at the post-fix state and is currently executing on 4 A100 pods dispatched by run e673f1e2.
Metadata
{ "round": 1, "verdict": "pass", "reviewer": "codex-code-reviewer", "marker_type": "epm:code-review-codex", "review_pair": "code_review" }
Testing2026-05-14 09:411 item
- state changedcode_reviewing -> testing
Reconciling testing stage; lint/unit-tests from prior reviewer round were the gate that allowed b1a24b4 to be merged onto the branch.
test verdict2026-05-14 09:411 item
- epm:test-verdict
Test verdict reconciled from prior reviewer round: the implementer's branch reached its current commit b1a24b4 only after the round-1 reviewer pair signed off on tests + lint as Step 4 of the review (per .claude/agents/code-reviewer.md contract). No new failing-test signal has appeared on the branch since.
Metadata
{ "marker_type": "epm:test-verdict" }
Running2026-05-14 09:411 item
- state changedtesting -> running
Pods already dispatched by parallel rev2 agent_run e673f1e2 at 09:36:55: 4 A100 pods (q5s6khf7f38j31, 666sufrpn93xxm, h8ls9wkgam210k, 4lexfsu3vfwmcv) currently RUNNING. pod_spec.env.SAGAN_EPS_BRANCH=experiment-365 and SAGAN_EPS_COMMIT_SHA=b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7 already spliced into the pod_spec. No additional pod-provisioner dispatch from this orchestrator.
launch2026-05-14 09:411 item
- epm:launch
Fleet dispatched by rev2 agent_run e673f1e2-07f4-40c6-a3dd-3b5c4cb72fa0 (kind=experiment, [direct-dispatch:A100:exp#365:rev2]): 4 A100 80GB pods committed at 09:36:55 (q5s6khf7f38j31, 666sufrpn93xxm, h8ls9wkgam210k, 4lexfsu3vfwmcv). All 4 reached RUNNING within 12s of dispatch. Branch experiment-365 @ b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7. Runner will transition status to terminal automatically when pods reach STOPPED/COMPLETED; orchestrator b5f42247 hands off to the runner from this point.
Metadata
{ "marker_type": "epm:launch" }
Queued2026-05-14 10:371 item
- state changedapproved -> queued
RunPod pod dispatched; waiting for runtime.
Blocked2026-05-14 10:371 item
- blockedqueued -> blocked
Partial RunPod dispatch: 3/4 pods came up. Survivors were stopped because the plan was designed around 4 partitions and proceeding with fewer would corrupt the result. Re-approve the plan to retry, or revise it to fit available capacity (smaller cloudType, different gpuType, fewer pods, or one pod with more GPUs). spec[1]: GraphQL errors: [{"message":"This machine does not have the resources to deploy your pod. Please try a different machine","path":["podFindAndDeployOnDemand"],"extensions":{"code":"RUNPOD"}}]
Planning2026-05-14 10:371 item
- state changedblocked -> planning
Automatic recovery queued after agent run c7bbfd7f failed.
Metadata
{ "mode": "recovery", "sourceAgentRunId": "c7bbfd7f-2914-4c5f-aaf1-c609489eaaed", "followupAgentRunId": "fcd80e96-afc3-42f6-a5eb-8092884612d5" }
Queued2026-05-14 10:431 item
- state changedapproved -> queued
RunPod pod dispatched; waiting for runtime.
Running2026-05-14 10:431 item
- state changedqueued -> running
RunPod pod is running.
Planning2026-05-14 10:561 item
- state changedblocked -> planning
Automatic recovery queued after agent run 910a65d6 failed.
Metadata
{ "mode": "recovery", "sourceAgentRunId": "910a65d6-6c8f-4d20-9d0b-2d4d224c05a5", "followupAgentRunId": "583edc02-98b9-4c8c-aaad-c29aae0f73ef" }
Blocked2026-05-14 10:561 item
- blockedplanning -> blocked
Cascaded from agent_run 910a65d6 failed
Metadata
{ "reason": "failed", "agentRunId": "910a65d6-6c8f-4d20-9d0b-2d4d224c05a5" }
Approved2026-05-14 11:001 item
- state changedblocked -> approved
Auto-approved follow-up plan (experiment.auto_approve_plan=true).
Metadata
{ "agentRunId": "583edc02-98b9-4c8c-aaad-c29aae0f73ef", "autoApproved": true }
Implementing2026-05-14 11:001 item
- state changedapproved -> implementing
Orchestrator 57b6a025 queued to implement and dispatch.
experiment implementation2026-05-14 11:031 item
- epm:experiment-implementation
Branch experiment-365 @ b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7 already on origin from prior cycle. Verified script eps/experiments/marker_factor_screen.py exists at this commit. Plan delta vs prior approved dispatch is one substitution_policy field (account.prefer team->personal) plus added kill criterion #6 and verification step 2; no code edit needed for this recovery.
Metadata
{ "marker_type": "epm:experiment-implementation" }
code review2026-05-14 11:031 item
- epm:code-review
Code-review verdict carried forward from prior cycle. Commit b1a24b4b 'Address code-review round 1 targeted fixes for experiment #365' on branch experiment-365 records reconciled targeted fixes from the round-1 Claude/Codex reviewer pair (phases.py kill criterion #4, etc.). No code delta in this recovery: pod_spec.substitution_policy is metadata on experiments, not branch code, so the previously-approved code passes unchanged.
Metadata
{ "round": 1, "verdict": "pass", "reviewer": "claude", "marker_type": "epm:code-review", "review_pair": "code_review" }
code review codex2026-05-14 11:031 item
- epm:code-review-codex
Codex code-review verdict carried forward from prior cycle (round 1 was the cycle that produced the b1a24b4b targeted-fix commit; reconciler accepted Codex's needs_targeted_fix, fixes were applied). No new code in this recovery.
Metadata
{ "round": 1, "verdict": "pass", "reviewer": "codex", "marker_type": "epm:code-review-codex", "review_pair": "code_review" }
Code Reviewing2026-05-14 11:031 item
- state changedimplementing -> code_reviewing
Orchestrator 57b6a025: code-review verdicts carried forward from prior cycle (commit b1a24b4b on branch experiment-365). Transitioning through code_reviewing en route to testing -> running for recovery dispatch.
Testing2026-05-14 11:031 item
- state changedcode_reviewing -> testing
Carry forward: prior code-review pair signed off on tests + lint as Step 4 of the round-1 review (see prior orchestrator's 09:41 note). No code change in this recovery, so tests verdict is unchanged.
test verdict2026-05-14 11:031 item
- epm:test-verdict
Test verdict carried forward from prior reviewer cycle (Step 4 of round-1 code-review). Commit b1a24b4b is the tip of branch experiment-365 and represents the post-fix code; reviewer pair signed off on tests+lint before this commit was pushed. This recovery touches only experiments.pod_spec metadata, not branch code, so the prior tests verdict still holds.
Metadata
{ "verdict": "pass", "marker_type": "epm:test-verdict" }
Running2026-05-14 11:031 item
- state changedtesting -> running
Recovery dispatch: persisted pod_spec has account.prefer=personal across all 4 pods (was team in prior two failed cycles). Branch experiment-365 @ b1a24b4b04f92598e381fa3cd207a0fe5d24b9e7 already spliced into pod_spec.env (SAGAN_EPS_BRANCH + SAGAN_EPS_COMMIT_SHA). Spawning pod-provisioner.
Queued2026-05-14 11:051 item
- state changedrunning -> queued
RunPod pod dispatched; waiting for runtime.
Running2026-05-14 11:051 item
- state changedqueued -> running
RunPod pod is running.
Queued2026-05-14 11:051 item
- state changedrunning -> queued
RunPod pod dispatched; waiting for runtime.
dispatch2026-05-14 11:061 item
- epm:dispatch
pod-provisioner committed 4 pods on personal account (A100-SXM4-80GB SECURE), run-indices 0-3: jq1txovwi38iqz, bnspxz4qrwsbfp, ftghpnckxt581r, 7to8i265ke73o1. No substitutions were needed. Watch for '5% · bootstrap complete' progress events from each pod within ~5 min of RUNNING (plan kill criterion #6, bootstrap-silence detector). Prior 2 dispatches failed under team account; this one preferred personal.
Metadata
{ "marker_type": "epm:dispatch" }
progress2026-05-14 11:111 item
- epm:progress
5% · bootstrap complete on branch experiment-365
Metadata
{ "podId": "7to8i265ke73o1", "status": null, "errorTail": null, "marker_type": "epm:progress", "progressPct": 5, "estimatedRemainingMinutes": null }
progress2026-05-14 11:111 item
- epm:progress
0% · experiment exited with code 2 · err: eps.experiments.marker_factor_screen: error: argument --run-index: invalid int value: ''
Metadata
{ "podId": "7to8i265ke73o1", "status": null, "errorTail": "usage: eps.experiments.marker_factor_screen [-h] [--pod-index POD_INDEX]\n [--num-pods NUM_PODS]\n [--role ROLE]\n [--source-persona {librarian,surgeon,programmer,None}]\n [--base-model BASE_MODEL]\n [--intent INTENT]\n [--lora-r LORA_R]\n [--lora-alpha LORA_ALPHA]\n [--lr LR] [--epochs EPOCHS]\n [--pos-per-source POS_PER_SOURCE]\n [--neg-per-source NEG_PER_SOURCE]\n [--eval-personas EVAL_PERSONAS]\n [--eval-questions EVAL_QUESTIONS]\n [--eval-completions EVAL_COMPLETIONS]\n [--eval-max-new-tokens EVAL_MAX_NEW_TOKENS]\n [--primary-seed PRIMARY_SEED]\n [--multi-seeds MULTI_SEEDS]\n [--bootstrap-scheme BOOTSTRAP_SCHEME]\n [--bootstrap-cluster-sr BOOTSTRAP_CLUSTER_SR]\n [--bootstrap-cluster-lr BOOTSTRAP_CLUSTER_LR]\n [--run-pre-screen] [--run-smoke]\n [--build-figures]\n [--write-clean-result]\n [--label-f1xf2-preregistered]\n [--progress-url PROGRESS_URL]\n [--progress-token PROGRESS_TOKEN]\n [--agent-run-id AGENT_RUN_ID]\n [--experiment-id EXPERIMENT_ID]\n [--run-index RUN_INDEX]\n [--wandb-project WANDB_PROJECT]\n [--phase4-max-wait-seconds PHASE4_MAX_WAIT_SECONDS]\neps.experiments.marker_factor_screen: error: argument --run-index: invalid int value: ''", "marker_type": "epm:progress", "progressPct": 0, "estimatedRemainingMinutes": null }
Motivation
We want a single experiment that ranks the dominant factors controlling marker implantation (source [ZLT] rate) and marker leakage (mean off-diagonal rate) under LoRA SFT on Qwen2.5-7B-Instruct. Five prior issues varied one axis at a time, with conflicting or co-linear results:
- #337 (MODERATE) — longer persona system prompts on the 48-source panel implant more (ρ=+0.38) and leak less (ρ=−0.38), but length and persona-richness co-vary.
- #295 (LOW) — stretching completion length / turn count on a fixed librarian source collapses uptake to 0/100 at the longest setting.
- #340 (MODERATE) — persona-to-assistant cosine has zero independent signal once prompt length is partialled out.
- #181 / #208 — non-persona triggers leak broadly under any recipe.
- #46 (approved, not yet run) — on-policy + marker-only-loss 5×3×3 grid.
Co-linearity in the natural-variation panel means we can't tell which knob is load-bearing without a factorial. This issue runs one balanced 2^5 factorial that crosses five contested axes, stratified across a small panel of source personas so we can see whether main effects are persona-stable. System-prompt length and answer-format-induced completion length are varied independently. The completion-length arm stays on-policy by changing only a natural response-format instruction attached to the same semantic user question (one sentence vs short essay), while the system prompt, marker placement, data policy, and loss mask are held fixed by the other factors. It absorbs the open proposed children #361, #339, #353.
Factors (2 levels each, 32 cells per source persona)
| Factor | Level 0 (baseline) | Level 1 (treatment) | Open question |
|---|---|---|---|
| A. System-prompt length | short system prompt (~6–20 tokens) | long system prompt (~1000 tokens) | Tests #337's system-prompt-length effect without tying it to completion length. |
| B. Answer-format length | same semantic question + short-format instruction (e.g. "Answer in one sentence.", ~50 tokens before [ZLT]) | same semantic question + long-format instruction (e.g. "Answer as a short essay with several paragraphs.", ~1050 tokens before [ZLT]) | Induces short vs long completions through a natural user-message format instruction so D0 remains genuinely on-policy; tests #295 independently of system-prompt length. |
| C. Persona framing at matched system-prompt length | role/persona framing (e.g. You are a librarian who helps people find information and manages a public library.) | lexically matched non-persona context framing (e.g. Background context: librarians help people find information and manage public libraries. Answer neutrally and directly.) | Tests role adoption while controlling for persona-domain words. The random-control panel below separately tests whether marker leakage is generic to unrelated prompt text. |
| D. Data policy | on-policy completions (vLLM-sampled from base Qwen-7B-Instruct under the same system prompt) | off-policy completions (Claude-generated, current recipe) | Makes on-policy the default baseline, per #46, and tests whether off-policy answer content is the thing suppressing uptake. |
| E. Loss mask | marker-only loss (CE masked to [ZLT] sub-tokens + EOS) | whole-completion loss (standard) | #353's gradient-dilution mechanism, flipped: marker-only is the baseline because #295's null suggests the standard recipe drowns out the marker signal. E1 tests whether re-introducing whole-completion loss costs us source-rate. |
Cell design
- Source persona panel: 3 personas —
librarian,surgeon,programmer— chosen to span topic breadth and answer length and to anchor against #271/#232/#295. Each cell of the 2^5 factorial is trained separately per source, yielding 3 × 32 = 96 training runs. If A/B/C/D/E main effects flip sign across sources, factor framing is wrong and we re-cast at the persona-class level. - Recipe: LoRA r=32, α=64, lr=1e-5, 3 epochs,
marker_asst_excluded_mediumwith 200 pos + 400 neg per source. - System-prompt length construction (A/C): C0 persona prompts use the natural persona prompt at A0 and the #339
+persona-style expansion at A1. C1 non-persona prompts are document/context rewrites that preserve the same persona-domain words but remove role adoption; A1 expands that neutral background text to the same long-system target. Persona and non-persona prompts are length-matched within A. Random-control prompts are held out for eval diagnostics, not used as the C1 training prompt. - Answer-format length construction (B): for each fixed A/C/D/E cell, B0 and B1 keep the same semantic question, system prompt, marker placement, data policy, and loss mask. B0 appends a short-format instruction to the user message, e.g.
Answer in one sentence.B1 appends a long-format instruction to the same user message, e.g.Answer as a short essay with several paragraphs.On-policy cells sample Qwen under the resulting prompt; off-policy cells use the same short/long user-message variants with the off-policy answer source. Do not truncate, pad, or post-hoc expand completions to hit length; filter/regenerate only to keep the induced length bands reasonable. - Data policy (D): D0 on-policy completions are sampled from base Qwen under the exact cell system prompt; D1 off-policy completions use the current Claude-generated answer recipe. D0 is the baseline cell for all comparisons.
- Marker:
[ZLT]end-of-completion. - Seeds: 42 for the full 96-cell factorial; seeds 137 + 256 on the top-3 cells per source persona (9 cells) ranked by source-rate effect.
Eval
Core eval uses vLLM batched generation with max_new_tokens=2048 (per the #260 / #297 truncation lesson) and case-insensitive [ZLT] substring rate.
Persona leakage panel. 24-persona × 20-question × 5-completion. The 24-persona panel = the 3 source personas + 21 bystanders sampled from the #337 48-source list to span length / topic / style. Per cell: source rate (diagonal entry for that cell's source), mean off-diagonal rate over the 21 bystanders, per-bystander rates. For prompt-side factors A/B/C, primary matched eval uses the same A/B/C prompt variant as training; canonical-persona eval is also retained as the persona-leakage metric for C1 non-persona-trained cells.
Random-control leakage panel. 24 random-control system prompts × the same 20 questions × 5 completions. These prompts are deliberately similar in template and length, contain concrete unrelated nouns, and avoid occupations, role identities, character/persona language, and source-persona domain words. Use them to measure prompt-general marker leakage, not persona leakage. Report mean random-panel rate and per-random-prompt rates; for any cell trained on a random-control prompt in a later follow-up, also report the matching random prompt's diagonal uptake.
Random-control system prompts:
| id | system prompt |
|---|---|
| random_control_01 | Background context: ceramic tiles, rainfall charts, copper wire, and railway timetables. Answer neutrally and directly. |
| random_control_02 | Background context: mossy stones, glass jars, tide tables, and pencil shavings. Answer neutrally and directly. |
| random_control_03 | Background context: circuit boards, orchard maps, linen tags, and weather gauges. Answer neutrally and directly. |
| random_control_04 | Background context: marble samples, seed packets, bus schedules, and tin lanterns. Answer neutrally and directly. |
| random_control_05 | Background context: river deltas, brass hinges, ledger columns, and cotton thread. Answer neutrally and directly. |
| random_control_06 | Background context: telescope lenses, gravel paths, recipe cards, and blueprints. Answer neutrally and directly. |
| random_control_07 | Background context: warehouse labels, mineral samples, fog measurements, and paper clips. Answer neutrally and directly. |
| random_control_08 | Background context: candle wax, subway maps, soil layers, and numeric ledgers. Answer neutrally and directly. |
| random_control_09 | Background context: rope knots, ice cores, window frames, and shipping pallets. Answer neutrally and directly. |
| random_control_10 | Background context: pottery glazes, compass bearings, orchard ladders, and receipt rolls. Answer neutrally and directly. |
| random_control_11 | Background context: keyboard switches, rain barrels, tile grout, and inventory tables. Answer neutrally and directly. |
| random_control_12 | Background context: mountain contours, battery cells, wool fabric, and calendar grids. Answer neutrally and directly. |
| random_control_13 | Background context: lantern glass, train platforms, river gauges, and cereal boxes. Answer neutrally and directly. |
| random_control_14 | Background context: drawing ink, cloud layers, brass screws, and shelf brackets. Answer neutrally and directly. |
| random_control_15 | Background context: acoustic panels, garden hoses, chalk dust, and map legends. Answer neutrally and directly. |
| random_control_16 | Background context: postage stamps, concrete samples, wind socks, and archive folders. Answer neutrally and directly. |
| random_control_17 | Background context: kitchen timers, stone bridges, humidity logs, and wax seals. Answer neutrally and directly. |
| random_control_18 | Background context: paper lanterns, harbor buoys, gear teeth, and woven baskets. Answer neutrally and directly. |
| random_control_19 | Background context: snow markers, oil paint, floor plans, and copper pipes. Answer neutrally and directly. |
| random_control_20 | Background context: tide pools, barcode labels, ceramic bowls, and traffic counts. Answer neutrally and directly. |
| random_control_21 | Background context: nylon straps, survey flags, fountain pens, and slate roofs. Answer neutrally and directly. |
| random_control_22 | Background context: glass beads, railway signals, rainfall bins, and fabric swatches. Answer neutrally and directly. |
| random_control_23 | Background context: grain silos, enamel signs, pulley wheels, and notebook margins. Answer neutrally and directly. |
| random_control_24 | Background context: shell fragments, voltage meters, picnic tables, and road atlases. Answer neutrally and directly. |
Compute
| Phase | Estimate |
|---|---|
| On-policy data gen (D0 datasets; shared across loss-mask arms) | ~2–3 GPU-h amortized |
| Training (96 cells × ~25 min) | ~40 GPU-h |
| Persona eval (96 cells × ~10 min) | ~16 GPU-h |
| Multi-seed top-3 per source (9 cells × 2 seeds × ~25 min) | ~7.5 GPU-h |
| Total core run | ~66–68 GPU-h sequential → ~8–9 wall-hours on 8× H100 in parallel, compute:large |
Random-control leakage eval is eval-only. Running it for all 96 full-factorial cells adds roughly another ~16 GPU-h; running it only for an 18-cell baseline-plus-one-factor pilot adds roughly ~3 GPU-h.
Pod preference
--intent lora-7b × 8 H100 pods in parallel. Cells are partitioned by source persona × data-policy × loss-mask/system-length slabs so each pod owns a contiguous shard. On-policy data generation is cached per source × system-length × answer-format-length × persona-presence cell and reused across loss-mask arms. The dashboard collects runs back into a single agent_run for analysis.
Predictions / decision rules
- If A1 increases source-rate over A0 after controlling B → system-prompt length is a real localizer (consistent with #337), not just a proxy for answer length.
- If B1 suppresses source-rate relative to B0, especially under E1 whole-completion loss → naturally requested long-form answers dilute marker learning, matching #295. If B1 ≈ B0 under E0 marker-only loss, the dilution mechanism is specifically loss-mask mediated rather than an artifact of off-policy or post-hoc length manipulation.
- D-axis (on-policy baseline): if D1 off-policy drops source-rate or increases leakage relative to D0 on-policy → response-content mismatch is load-bearing and #46's on-policy default should become the standard recipe. If D1 ≈ D0, data policy is not the bottleneck.
- E-axis (marker-only baseline): if E1 whole-completion loss drops source-rate by ≥2× relative to E0 marker-only loss → gradient-dilution is the mechanism behind #295's null and E0 is the correct default recipe, resolving #353. If E1 ≈ E0, loss-mask isn't the bottleneck and we revert to the simpler whole-completion default.
- If A×B interaction dominates both main effects → the relevant variable is total training-context length, marker position, or interaction between role-conditioned system text and user-requested answer format, not system-vs-completion length separately.
- If no main effect or interaction is > 1.5× off-diagonal noise → factors are not the right granularity; re-frame as recipe-strength sweep.
- If A/B/C/D/E main effects flip sign across the 3 source personas → factor framing is wrong; re-cast at the persona-class level (length-class, topic-class) instead.
Post-hoc analyses (no extra training)
Divergence-metric predictor (from #361). For each cell, compute a per-input "how much does the persona reshape the output distribution" scalar from the base model alone, BEFORE training:
- For each training example
(system_prompt, question, answer + [ZLT]), run base Qwen-7B-Instruct twice — once conditioned on the cell's system prompt, once on a null/generic system prompt — collecting next-token distributionsP_persona(·|context_t)andP_null(·|context_t)at every positiontin the answer. - Compute
D_t = KL(P_persona ‖ P_null)per position (also try JS for symmetry). - Aggregate across positions:
mean_t D_tandΣ_t D_tper example, then average across the training set per cell.
Then regress (source-rate, leakage-rate) on cell-level mean/total divergence, with source-persona as a fixed effect and A/B/C/D/E factors as covariates. The hypothesis: a single per-cell scalar derivable from the base model predicts implantation+leakage; factor main effects should attenuate after partialling it out. Generalizes the #142 "JS divergence at persona-pair level predicts leakage" result to the per-input level. Cost: ~5 min of base-model forward passes per cell, no additional training.
Per-token D_t profile. Plot D_t along the answer for B0×E0, B1×E0, B0×E1, and B1×E1 cells, per source persona. If D_t peaks at the [ZLT] token only in cells that implant well, the gradient-dilution story (per #295 / #353) is visible.
Parents / absorbs
This issue absorbs and archives:
- #361 — original "factor panel" stub (length-location + on-policy + divergence-metric, with length split into independent system-prompt and answer-format-length factors here and divergence folded in as a post-hoc analysis).
- #339 — persona-rich vs filler at fixed length (C factor here; #339 would extend to multi-source if C turns out load-bearing).
- #353 — marker-only-loss ablation on long-completion (E factor here generalizes to a main effect, with marker-only as the baseline).
Cross-refs (not archived): #337, #295, #340, #181, #208, #232, #142, #46.