cflx 0.6.153

Conflux – a spec-driven parallel coding orchestrator that runs AI agents on git worktrees
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
use agent_skills_rs::embedded::register_embedded_skill;
use agent_skills_rs::types::Skill;
use anyhow::Result;

// cflx-proposal skill files
const CFLX_PROPOSAL_SKILL_MD: &str = include_str!("../skills/cflx-proposal/SKILL.md");

// cflx-workflow skill files (compatibility router)
const CFLX_WORKFLOW_SKILL_MD: &str = include_str!("../skills/cflx-workflow/SKILL.md");
const CFLX_WORKFLOW_REF_ACCEPT: &str =
    include_str!("../skills/cflx-workflow/references/cflx-accept.md");
const CFLX_WORKFLOW_REF_APPLY: &str =
    include_str!("../skills/cflx-workflow/references/cflx-apply.md");
const CFLX_WORKFLOW_REF_ARCHIVE: &str =
    include_str!("../skills/cflx-workflow/references/cflx-archive.md");

// cflx-run skill files
const CFLX_RUN_SKILL_MD: &str = include_str!("../skills/cflx-run/SKILL.md");
const CFLX_RUN_REF: &str = include_str!("../skills/cflx-run/references/cflx-run.md");

// Operation-specific skill files
const CFLX_ANALYZE_SKILL_MD: &str = include_str!("../skills/cflx-analyze/SKILL.md");
const CFLX_APPLY_SKILL_MD: &str = include_str!("../skills/cflx-apply/SKILL.md");
const CFLX_APPLY_REF: &str = include_str!("../skills/cflx-apply/references/cflx-apply.md");
const CFLX_REJECTING_SKILL_MD: &str = include_str!("../skills/cflx-rejecting/SKILL.md");
const CFLX_REJECTION_GUIDE_SKILL_MD: &str = include_str!("../skills/cflx-rejection-guide/SKILL.md");
const CFLX_REJECTION_GUIDE_REF: &str =
    include_str!("../skills/cflx-rejection-guide/references/guide.md");
const CFLX_CLEANUP_REVIEW_SKILL_MD: &str = include_str!("../skills/cflx-cleanup-review/SKILL.md");
const CFLX_ACCEPT_SKILL_MD: &str = include_str!("../skills/cflx-accept/SKILL.md");
const CFLX_ACCEPT_WITH_SPECA_SKILL_MD: &str =
    include_str!("../skills/cflx-accept-with-speca/SKILL.md");
#[cfg(test)]
const CFLX_ACCEPT_COMMAND_MD: &str = include_str!("../.opencode/commands/cflx-accept.md");
const CFLX_ARCHIVE_SKILL_MD: &str = include_str!("../skills/cflx-archive/SKILL.md");
const CFLX_ARCHIVE_REF: &str = include_str!("../skills/cflx-archive/references/cflx-archive.md");
const CFLX_RESOLVE_SKILL_MD: &str = include_str!("../skills/cflx-resolve/SKILL.md");

/// Return all cflx bundled skills with their auxiliary files embedded at compile time.
pub fn get_cflx_embedded_skills() -> Result<Vec<Skill>> {
    let proposal = register_embedded_skill(CFLX_PROPOSAL_SKILL_MD, &[])?;

    let workflow = register_embedded_skill(
        CFLX_WORKFLOW_SKILL_MD,
        &[
            ("references/cflx-accept.md", CFLX_WORKFLOW_REF_ACCEPT),
            ("references/cflx-apply.md", CFLX_WORKFLOW_REF_APPLY),
            ("references/cflx-archive.md", CFLX_WORKFLOW_REF_ARCHIVE),
        ],
    )?;

    let run = register_embedded_skill(
        CFLX_RUN_SKILL_MD,
        &[("references/cflx-run.md", CFLX_RUN_REF)],
    )?;

    let analyze = register_embedded_skill(CFLX_ANALYZE_SKILL_MD, &[])?;

    let apply = register_embedded_skill(
        CFLX_APPLY_SKILL_MD,
        &[("references/cflx-apply.md", CFLX_APPLY_REF)],
    )?;

    let rejecting = register_embedded_skill(CFLX_REJECTING_SKILL_MD, &[])?;
    let rejection_guide = register_embedded_skill(
        CFLX_REJECTION_GUIDE_SKILL_MD,
        &[("references/guide.md", CFLX_REJECTION_GUIDE_REF)],
    )?;

    let cleanup_review = register_embedded_skill(CFLX_CLEANUP_REVIEW_SKILL_MD, &[])?;

    let accept = register_embedded_skill(CFLX_ACCEPT_SKILL_MD, &[])?;
    let accept_with_speca = register_embedded_skill(CFLX_ACCEPT_WITH_SPECA_SKILL_MD, &[])?;

    let archive = register_embedded_skill(
        CFLX_ARCHIVE_SKILL_MD,
        &[("references/cflx-archive.md", CFLX_ARCHIVE_REF)],
    )?;

    let resolve = register_embedded_skill(CFLX_RESOLVE_SKILL_MD, &[])?;

    Ok(vec![
        proposal,
        workflow,
        run,
        analyze,
        apply,
        rejecting,
        rejection_guide,
        cleanup_review,
        accept,
        accept_with_speca,
        archive,
        resolve,
    ])
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_embedded_skills_count() {
        let skills = get_cflx_embedded_skills().expect("Failed to get embedded skills");
        assert_eq!(skills.len(), 12, "Expected exactly 12 embedded skills");
    }

    #[test]
    fn test_embedded_skills_names() {
        let skills = get_cflx_embedded_skills().unwrap();
        let names: Vec<&str> = skills.iter().map(|s| s.name.as_str()).collect();
        let expected = [
            "cflx-proposal",
            "cflx-workflow",
            "cflx-run",
            "cflx-analyze",
            "cflx-apply",
            "cflx-rejecting",
            "cflx-rejection-guide",
            "cflx-cleanup-review",
            "cflx-accept",
            "cflx-accept-with-speca",
            "cflx-archive",
            "cflx-resolve",
        ];
        for name in &expected {
            assert!(
                names.contains(name),
                "Expected {} skill, found: {:?}",
                name,
                names
            );
        }
    }

    #[test]
    fn test_embedded_skills_have_auxiliary_files() {
        let skills = get_cflx_embedded_skills().unwrap();

        // cflx-proposal: no scripts/cflx.py
        let proposal = skills.iter().find(|s| s.name == "cflx-proposal").unwrap();
        assert!(
            !proposal.auxiliary_files.contains_key("scripts/cflx.py"),
            "cflx-proposal must NOT have scripts/cflx.py (replaced by native CLI)"
        );

        // cflx-workflow: compatibility router with references, no scripts/cflx.py
        let workflow = skills.iter().find(|s| s.name == "cflx-workflow").unwrap();
        assert!(
            !workflow.auxiliary_files.contains_key("scripts/cflx.py"),
            "cflx-workflow must NOT have scripts/cflx.py (replaced by native CLI)"
        );
        assert!(
            workflow
                .auxiliary_files
                .contains_key("references/cflx-accept.md"),
            "cflx-workflow must have references/cflx-accept.md"
        );
        assert!(
            workflow
                .auxiliary_files
                .contains_key("references/cflx-apply.md"),
            "cflx-workflow must have references/cflx-apply.md"
        );
        assert!(
            workflow
                .auxiliary_files
                .contains_key("references/cflx-archive.md"),
            "cflx-workflow must have references/cflx-archive.md"
        );

        // cflx-run: has reference
        let run = skills.iter().find(|s| s.name == "cflx-run").unwrap();
        assert!(
            run.auxiliary_files.contains_key("references/cflx-run.md"),
            "cflx-run must have references/cflx-run.md"
        );

        // cflx-apply: has reference
        let apply = skills.iter().find(|s| s.name == "cflx-apply").unwrap();
        assert!(
            apply
                .auxiliary_files
                .contains_key("references/cflx-apply.md"),
            "cflx-apply must have references/cflx-apply.md"
        );
        assert!(
            !apply.auxiliary_files.contains_key("scripts/cflx.py"),
            "cflx-apply must NOT have scripts/cflx.py"
        );

        // cflx-archive: has reference
        let archive = skills.iter().find(|s| s.name == "cflx-archive").unwrap();
        assert!(
            archive
                .auxiliary_files
                .contains_key("references/cflx-archive.md"),
            "cflx-archive must have references/cflx-archive.md"
        );
        assert!(
            !archive.auxiliary_files.contains_key("scripts/cflx.py"),
            "cflx-archive must NOT have scripts/cflx.py"
        );

        let rejection_guide = skills
            .iter()
            .find(|s| s.name == "cflx-rejection-guide")
            .unwrap();
        assert!(
            rejection_guide
                .auxiliary_files
                .contains_key("references/guide.md"),
            "cflx-rejection-guide must have references/guide.md"
        );

        // Operation-specific skills without auxiliary files: no scripts/cflx.py
        for name in &[
            "cflx-analyze",
            "cflx-rejecting",
            "cflx-rejection-guide",
            "cflx-cleanup-review",
            "cflx-accept",
            "cflx-accept-with-speca",
            "cflx-resolve",
        ] {
            let skill = skills.iter().find(|s| s.name == *name).unwrap();
            assert!(
                !skill.auxiliary_files.contains_key("scripts/cflx.py"),
                "{} must NOT have scripts/cflx.py",
                name
            );
        }
    }

    // --- Prompt ownership drift-detection tests ---
    // These tests verify that the workflow-split ownership boundaries are maintained:
    // - cflx-accept skill owns the portable acceptance operation interface
    // - Rust prompt builders inject variable context rather than provider-specific checklists
    // - Embedded skills maintain their documented role boundaries

    /// Phrases that indicate provider-specific command-template coupling or
    /// apply-loop mutation workflow details that must not become the portable skill interface.
    const ACCEPTANCE_PORTABILITY_FORBIDDEN_PHRASES: &[&str] = &[
        "single source of truth",
        "command template as authoritative",
        "command-template contract",
        "opencode",
        "OpenCode",
        "agent-exec run --",
        "On mini",
        "## Acceptance #",
    ];

    #[test]
    fn test_cflx_accept_skill_defines_portable_contract() {
        for required in &[
            "portable Conflux acceptance interface",
            "agent-runtime independent",
            "Runtime-specific entrypoints are adapters",
            "{\"acceptance\":\"pass\"}",
            "{\"acceptance\":\"fail\",\"findings\":[\"<evidence>\"]}",
            "{\"acceptance\":\"continue\"}",
            "{\"acceptance\":\"gated\"}",
            "ACCEPTANCE: PASS",
            "ACCEPTANCE: FAIL",
            "ACCEPTANCE: CONTINUE",
            "ACCEPTANCE: GATED",
        ] {
            assert!(
                CFLX_ACCEPT_SKILL_MD.contains(required),
                "cflx-accept SKILL.md must define portable acceptance contract: {required}"
            );
        }
        assert!(
            !CFLX_ACCEPT_SKILL_MD.contains(".opencode/commands/cflx-accept.md"),
            "cflx-accept SKILL.md must not require runtime-specific command files for its interface"
        );
        for phrase in ACCEPTANCE_PORTABILITY_FORBIDDEN_PHRASES {
            assert!(
                !CFLX_ACCEPT_SKILL_MD.contains(phrase),
                "cflx-accept SKILL.md must not contain provider-coupled phrase '{}'",
                phrase
            );
        }
    }

    #[test]
    fn test_cflx_accept_with_speca_skill_contract() {
        let skills = get_cflx_embedded_skills().unwrap();
        let skill = skills
            .iter()
            .find(|s| s.name == "cflx-accept-with-speca")
            .expect("cflx-accept-with-speca must be embedded");

        assert_eq!(skill.name, "cflx-accept-with-speca");
        for required in &[
            "drop-in replacement for `cflx-accept`",
            "exact same verdict output interface as `cflx-accept`",
            "agent-runtime independent",
            "Runtime-specific entrypoints are adapters",
            "{\"acceptance\":\"pass\"}",
            "{\"acceptance\":\"fail\",\"findings\":[\"<evidence>\"]}",
            "{\"acceptance\":\"continue\"}",
            "{\"acceptance\":\"gated\"}",
            "ACCEPTANCE: PASS",
            "ACCEPTANCE: FAIL",
            "ACCEPTANCE: CONTINUE",
            "ACCEPTANCE: GATED",
        ] {
            assert!(
                CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(required),
                "SPECA acceptance skill must preserve portable cflx-accept interface: {required}"
            );
        }
        assert!(
            !CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(".opencode/commands/cflx-accept.md"),
            "SPECA acceptance skill must not require runtime-specific command files for its interface"
        );
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("Derive checkable properties")
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("Attempt proof or falsification"),
            "SPECA acceptance skill must include property derivation and proof-attempt guidance"
        );
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("standard JSON `fail` verdict")
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("findings"),
            "SPECA acceptance skill must map blocking property failures to standard fail findings"
        );
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("unavailable SPECA tooling")
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD
                    .contains("Never treat unavailable SPECA tooling as an automatic pass"),
            "SPECA acceptance skill must define fallback behavior when tooling is unavailable"
        );
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("Do not ask the user questions"),
            "SPECA acceptance skill must remain autonomous"
        );
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("out-of-worktree durable"),
            "SPECA acceptance skill must preserve workspace-local workflow-control constraints"
        );
    }

    #[test]
    fn test_cflx_accept_with_speca_documents_official_runner_adapter() {
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("NyxFoundation/speca")
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("$SPECA_CHECKOUT")
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("~/services/speca/")
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(
                    "~/tmp/cflx-speca/<workspace-key>/run/<change-id>/<attempt-id>/speca/"
                )
                && CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("uv run python3 scripts/run_phase.py"),
            "SPECA acceptance skill must document the official runner checkout and command shape"
        );
        assert!(
            CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("Official NyxFoundation/speca Runner Adapter"),
            "SPECA acceptance skill must include a dedicated official runner adapter section"
        );
    }

    #[test]
    fn test_cflx_accept_with_speca_keeps_runner_artifacts_outside_worktree() {
        for required in &[
            "~/tmp/cflx-speca/<workspace-key>/",
            "~/tmp/cflx-speca/<workspace-key>/input/<change-id>/<attempt-id>/",
            "~/tmp/cflx-speca/<workspace-key>/output/<change-id>/<attempt-id>/",
            "outside the target Conflux worktree",
            "Do not clone or install NyxFoundation/speca from this acceptance skill",
            "Deleting the out-of-worktree SPECA input/output/log/cache directories must not change the next Conflux action",
            "repository/workspace evidence is authoritative",
        ] {
            assert!(
                CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(required),
                "SPECA acceptance skill must contain workspace-boundary guidance: {required}"
            );
        }
        assert!(
            !CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains("~/tmp/speca-conflux-input/<change-id>/")
                && !CFLX_ACCEPT_WITH_SPECA_SKILL_MD
                    .contains("~/tmp/speca-conflux-output/<change-id>/"),
            "SPECA acceptance skill must not recommend global change-id-only input/output paths"
        );
    }

    #[test]
    fn test_cflx_accept_with_speca_documents_prerequisites_and_fallback() {
        for required in &[
            "`uv` is installed and available on `PATH`",
            "Python dependencies are ready",
            "Required model/API/session/auth access is available",
            "record the limitation in human-readable reasoning and continue with manual SPECA-style property review",
            "Never treat runner unavailability, setup failure, missing auth, or inconclusive output as an automatic pass",
        ] {
            assert!(
                CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(required),
                "SPECA acceptance skill must contain prerequisite/fallback guidance: {required}"
            );
        }
    }

    #[test]
    fn test_cflx_accept_with_speca_documents_runtime_neutral_long_runner_work() {
        for required in &[
            "Use the current runtime's standard long-running-command mechanism",
            "uv sync",
            "uv run python3 scripts/run_phase.py",
        ] {
            assert!(
                CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(required),
                "SPECA runner setup/execution guidance must remain runtime-neutral: {required}"
            );
        }
        for forbidden in &["agent-exec run --", "On mini", "opencode", "OpenCode"] {
            assert!(
                !CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(forbidden),
                "SPECA runner guidance must not depend on a specific harness: {forbidden}"
            );
        }
    }

    #[test]
    fn test_cflx_accept_with_speca_skill_remains_portable() {
        for phrase in ACCEPTANCE_PORTABILITY_FORBIDDEN_PHRASES {
            assert!(
                !CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(phrase),
                "cflx-accept-with-speca SKILL.md must not contain provider-coupled phrase '{}'",
                phrase
            );
        }
    }

    #[test]
    fn test_cflx_accept_with_speca_skill_has_no_speca_terminal_protocol() {
        for forbidden in &[
            "SPECA: PASS",
            "SPECA: FAIL",
            "SPECA: CONTINUE",
            "SPECA: GATED",
        ] {
            assert!(
                !CFLX_ACCEPT_WITH_SPECA_SKILL_MD.contains(forbidden),
                "cflx-accept-with-speca must not introduce terminal protocol '{}'",
                forbidden
            );
        }
    }

    #[test]
    fn test_acceptance_command_template_enforces_behavior_task_adequacy_in_acceptance() {
        assert!(
            CFLX_ACCEPT_COMMAND_MD
                .contains("Behavior-task adequacy check for behavior-changing work"),
            "acceptance command template must require behavior-task adequacy review in acceptance"
        );
        assert!(
            CFLX_ACCEPT_COMMAND_MD.contains(
                "Do NOT defer this class of issue to archive; acceptance owns this judgment."
            ),
            "acceptance command template must keep behavior-task adequacy ownership in acceptance"
        );
    }

    #[test]
    fn test_rust_prompt_builder_does_not_contain_acceptance_checklist() {
        // The ARCHIVE_READINESS_CONTEXT is the only fixed content the Rust prompt builder
        // injects. Verify it doesn't contain the portable acceptance checklist
        // owned by the acceptance operation skill or runtime-specific adapters.
        let archive_ctx = crate::agent::prompt::tests::get_archive_readiness_context();
        let checklist_phrases = [
            "Output format (output exactly ONCE",
            "CRITICAL formatting rule:",
            "Required checks:",
            "Implementation Blocker review:",
        ];
        for phrase in &checklist_phrases {
            assert!(
                !archive_ctx.contains(phrase),
                "ARCHIVE_READINESS_CONTEXT must NOT contain acceptance checklist phrase '{}'",
                phrase
            );
        }
    }

    #[test]
    fn test_rejecting_skill_documents_block_tri_state_contract() {
        for required in &[
            "REJECTION_REVIEW: CONFIRM",
            "REJECTION_REVIEW: RESUME",
            "REJECTION_REVIEW: BLOCK",
            "CONFIRM`: terminal rejection",
            "RESUME`: reject proposal is dismissed",
            "BLOCK`: reject proposal describes a real non-terminal blocker",
        ] {
            assert!(
                CFLX_REJECTING_SKILL_MD.contains(required),
                "cflx-rejecting SKILL.md must document tri-state rejecting outcome: {required}"
            );
        }
        assert!(
            !CFLX_REJECTING_SKILL_MD.contains("CONFIRM|RESUME")
                && !CFLX_REJECTING_SKILL_MD.contains("CONFIRM or RESUME"),
            "cflx-rejecting must not describe rejecting review as confirm/resume-only"
        );
    }

    #[test]
    fn test_apply_and_acceptance_skills_keep_recoverable_infra_blockers_non_terminal() {
        for (label, content) in &[
            ("cflx-apply", CFLX_APPLY_SKILL_MD),
            ("cflx-accept", CFLX_ACCEPT_SKILL_MD),
            ("cflx-workflow", CFLX_WORKFLOW_SKILL_MD),
        ] {
            assert!(
                content.contains("infrastructure")
                    && content.contains("non-terminal")
                    && content.contains("stalled"),
                "{label} must route recoverable infrastructure blockers to non-terminal stalled holds"
            );
            assert!(
                content.contains("Docker")
                    && content.contains("credential")
                    && content.contains("pending"),
                "{label} must mention representative recoverable blocker classes"
            );
        }
        assert!(
            CFLX_APPLY_SKILL_MD.contains("do not create `REJECTED.md` for these recoverable cases"),
            "cflx-apply must prohibit REJECTED.md for recoverable infrastructure blockers"
        );
    }

    #[test]
    fn test_acceptance_skills_frame_blockers_as_stalled_holds() {
        for (label, content) in &[
            ("cflx-accept", CFLX_ACCEPT_SKILL_MD),
            ("cflx-accept-with-speca", CFLX_ACCEPT_WITH_SPECA_SKILL_MD),
            ("cflx-workflow", CFLX_WORKFLOW_SKILL_MD),
            (
                "cflx-workflow references/cflx-accept.md",
                CFLX_WORKFLOW_REF_ACCEPT,
            ),
            (".opencode/commands/cflx-accept.md", CFLX_ACCEPT_COMMAND_MD),
        ] {
            assert!(
                content.contains("stalled") && content.contains("Implementation Blocker"),
                "{label} must describe valid Implementation Blockers as stalled holds"
            );
            assert!(
                content.contains("compatibility") && content.contains("{\"acceptance\":\"gated\"}"),
                "{label} must keep gated as a parser-compatible handoff token"
            );
            assert!(
                !content.contains("- GATED:") && !content.contains("FAIL vs GATED"),
                "{label} must not use GATED as the primary blocker outcome label or rubric"
            );
            assert!(
                !content.contains("STALLED HOLD (primary): {\"acceptance\":\"stalled\"}")
                    && !content.contains("- STALLED:    {\"acceptance\":\"stalled\"}"),
                "{label} must not define a stalled JSON verdict as a supported output before parser support exists"
            );
        }
    }

    #[test]
    fn test_acceptance_verdict_contract_consistency() {
        // Verify canonical verdict markers are documented consistently
        // across the parser, OpenCode adapter reference, and the cflx-workflow skill.
        let canonical_markers = [
            "ACCEPTANCE: PASS",
            "ACCEPTANCE: FAIL",
            "ACCEPTANCE: CONTINUE",
            "ACCEPTANCE: GATED",
        ];

        // cflx-workflow SKILL.md must mention all canonical markers
        for marker in &canonical_markers {
            assert!(
                CFLX_WORKFLOW_SKILL_MD.contains(marker),
                "cflx-workflow SKILL.md must document verdict marker '{}'",
                marker
            );
        }

        // cflx-workflow references/cflx-accept.md must mention all canonical markers
        for marker in &canonical_markers {
            assert!(
                CFLX_WORKFLOW_REF_ACCEPT.contains(marker),
                "cflx-workflow references/cflx-accept.md must document verdict marker '{}'",
                marker
            );
        }

        // Legacy compatibility marker should remain documented during migration.
        assert!(
            CFLX_WORKFLOW_REF_ACCEPT.contains("ACCEPTANCE: BLOCKED"),
            "cflx-workflow references/cflx-accept.md must document legacy acceptance marker 'ACCEPTANCE: BLOCKED'"
        );
    }

    #[test]
    fn test_cflx_workflow_verdict_format_prohibitions() {
        // Verify the cflx-workflow skill includes formatting prohibitions
        // to prevent drift in legacy-path output.
        assert!(
            CFLX_WORKFLOW_SKILL_MD.contains("Do NOT wrap the verdict"),
            "cflx-workflow SKILL.md must include verdict formatting prohibition"
        );
    }

    #[test]
    fn test_cflx_workflow_reference_documents_strict_canonical_contract() {
        // The runtime parser enforces standalone-line canonical matching and
        // rejects trailing-text/heading-concatenation verdicts. The embedded
        // workflow reference MUST document both the trailing-text rejection
        // example and the heading-concatenation rejection example so agents
        // are warned about the failure modes that drove this contract.
        for required in &[
            "NO trailing text",
            "PASSAll",
            "NO heading concatenation",
            "PASS## Acceptance Review Summary",
        ] {
            assert!(
                CFLX_WORKFLOW_REF_ACCEPT.contains(required),
                "cflx-workflow references/cflx-accept.md must document '{}'",
                required
            );
        }
    }
}