a3s 0.10.4

a3s — A3S coding agent CLI; `a3s code` launches the interactive TUI
Documentation
use super::test_support::*;
use super::*;

#[test]
fn one_valid_provenance_edge_cannot_hide_an_unmatched_source_target() {
    let spec = spec(
        EvidenceScope::Web,
        vec![
            dimension("alpha", &["alpha-target"]),
            dimension("beta", &["beta-target"]),
        ],
        vec![
            named_target(
                "alpha-target",
                "alpha_family",
                SourceRole::Primary,
                SourceIdentity::Domain("alpha.example.test".to_string()),
            ),
            named_target(
                "beta-target",
                "beta_family",
                SourceRole::Primary,
                SourceIdentity::Domain("beta.example.test".to_string()),
            ),
        ],
        budget(2, 2),
    );
    let plan = plan(
        &spec,
        vec![
            query(
                "q-alpha",
                AcquisitionTransport::Web,
                QueryMode::Exact,
                &["alpha"],
                &["alpha-target"],
                1,
            ),
            query(
                "q-beta",
                AcquisitionTransport::Web,
                QueryMode::Exact,
                &["beta"],
                &["beta-target"],
                1,
            ),
        ],
        vec![],
    );
    let contract = validate_research_contract(spec, plan).expect("two-target contract");
    let chunks = vec![SourceChunk {
        id: "source-alpha:chunk:1".to_string(),
        text: "Alpha evidence only.".to_string(),
    }];
    let catalog = SourceCatalog {
        spec_digest: research_spec_digest(&contract.spec),
        attempts: vec![AcquisitionAttempt {
            query_id: "q-alpha".to_string(),
            source_target_ids: vec!["alpha-target".to_string()],
            outcome: AcquisitionOutcome::Fetched,
        }],
        sources: vec![SourceRecord {
            id: "source-alpha".to_string(),
            title: "Alpha source".to_string(),
            requested_anchor: "https://alpha.example.test/source".to_string(),
            canonical_anchor: "https://alpha.example.test/source".to_string(),
            captured_at: "2026-07-21T00:00:00Z".to_string(),
            provenance: vec![
                SourceProvenance {
                    query_id: "q-alpha".to_string(),
                    source_target_id: "alpha-target".to_string(),
                },
                SourceProvenance {
                    query_id: "q-alpha".to_string(),
                    source_target_id: "beta-target".to_string(),
                },
            ],
            content_digest: source_content_digest(&chunks),
            chunks,
        }],
    };

    assert!(matches!(
        validate_source_catalog(&contract, &catalog),
        Err(CatalogError::QueryTargetMismatch { query_id, target_id })
            if query_id == "q-alpha" && target_id == "beta-target"
    ));
}

#[test]
fn source_provenance_requires_a_matching_fetched_attempt() {
    let spec = spec(
        EvidenceScope::Web,
        vec![dimension("alpha", &["alpha-target"])],
        vec![named_target(
            "alpha-target",
            "alpha_family",
            SourceRole::Primary,
            SourceIdentity::Domain("alpha.example.test".to_string()),
        )],
        budget(1, 1),
    );
    let plan = plan(
        &spec,
        vec![query(
            "q-alpha",
            AcquisitionTransport::Web,
            QueryMode::Exact,
            &["alpha"],
            &["alpha-target"],
            1,
        )],
        vec![],
    );
    let contract = validate_research_contract(spec, plan).expect("attempt contract");
    let chunks = vec![SourceChunk {
        id: "source-alpha:chunk:1".to_string(),
        text: "Alpha evidence only.".to_string(),
    }];
    let catalog = SourceCatalog {
        spec_digest: research_spec_digest(&contract.spec),
        attempts: vec![AcquisitionAttempt {
            query_id: "q-alpha".to_string(),
            source_target_ids: vec!["alpha-target".to_string()],
            outcome: AcquisitionOutcome::Failed {
                reason: "The fetch failed before source admission.".to_string(),
            },
        }],
        sources: vec![SourceRecord {
            id: "source-alpha".to_string(),
            title: "Alpha source".to_string(),
            requested_anchor: "https://alpha.example.test/source".to_string(),
            canonical_anchor: "https://alpha.example.test/source".to_string(),
            captured_at: "2026-07-21T00:00:00Z".to_string(),
            provenance: vec![SourceProvenance {
                query_id: "q-alpha".to_string(),
                source_target_id: "alpha-target".to_string(),
            }],
            content_digest: source_content_digest(&chunks),
            chunks,
        }],
    };

    assert!(matches!(
        validate_source_catalog(&contract, &catalog),
        Err(CatalogError::MissingFetchedAttempt {
            source_id,
            query_id,
            target_id,
        }) if source_id == "source-alpha"
            && query_id == "q-alpha"
            && target_id == "alpha-target"
    ));
}