diff --git a/.gitignore b/.gitignore index ab18dc01..05abfb2c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ website-bot.db-wal # Generated launch-env / deploy-secret reports (per-run artifacts, not source) validation/launch_env_report.json validation/deploy_secrets_report.json +validation/validation_report.yaml astro_template/validation/*.jsonl # Test coverage artifacts (generated by c8/node --test, not source) @@ -59,3 +60,11 @@ reports/test-runs/**/*.pem reports/test-runs/**/*.key reports/test-runs/**/*secret* reports/test-runs/**/*credential* + +# Non-npm lockfiles — this repo is npm-only (CI pins PACKAGE_MANAGER=npm and +# tracks package-lock.json). A stray lockfile from another package manager is +# container debris, and the l9-lint-test workflows' pnpm/yarn arms would treat +# it as load-bearing the moment PACKAGE_MANAGER changed. +pnpm-lock.yaml +yarn.lock +bun.lockb diff --git a/examples/quantum-ai-partners/domain_spec.normalized.yaml b/examples/quantum-ai-partners/domain_spec.normalized.yaml index 0e026a0a..be2de44a 100644 --- a/examples/quantum-ai-partners/domain_spec.normalized.yaml +++ b/examples/quantum-ai-partners/domain_spec.normalized.yaml @@ -27,6 +27,9 @@ routes: - process - faq - final_cta + purpose: Position the company, route the three audience segments, show the layered services model, and capture email conversions. + template: homepage + priority: 1 - slug: /services title: Services components: @@ -36,6 +39,9 @@ routes: - process - faq - cta + purpose: Explain the three service lines and how they compose into one layered engagement. + template: services_page + priority: 2 - slug: /approach title: Approach components: @@ -45,6 +51,9 @@ routes: - stack - faq - cta + purpose: Explain the layered systems methodology — strategy, build, production hardening — with real depth, no hype. + template: approach_page + priority: 3 - slug: /about title: About components: @@ -52,18 +61,27 @@ routes: - positioning - trust_bar - cta + purpose: State who Quantum AI Partners is and what it stands for, without unverified credentials. + template: about_page + priority: 4 - slug: /faq title: FAQ components: - hero - faq - cta + purpose: Answer cost, process, technology, security, and engagement questions. + template: faq_page + priority: 5 - slug: /contact title: Contact components: - hero - contact_options - cta + purpose: Primary conversion page — email and intro-call path. + template: contact_page + priority: 6 seo_contract: site_url: https://www.quantumaipartners.com target_keywords: @@ -83,10 +101,46 @@ seo_contract: - AI consulting engagement model - Quantum AI Partners - AI consultancy Quantum AI Partners + route_targets: + - cluster_name: ai_consulting + target_page: /services + intent: service_provider + keywords: + - AI consulting + - AI consulting services + - AI consulting firm + - enterprise AI consulting + - cluster_name: ai_implementation + target_page: /approach + intent: service_provider + keywords: + - AI implementation + - LLM integration + - custom AI development + - AI agent development + - cluster_name: ai_strategy + target_page: /services + intent: service_provider + keywords: + - AI strategy + - AI adoption roadmap + - AI readiness assessment + - cluster_name: ai_faq + target_page: /faq + intent: informational + keywords: + - AI consulting FAQ + - how much does AI consulting cost + - AI consulting engagement model + - cluster_name: brand + target_page: /about + intent: informational + keywords: + - Quantum AI Partners + - AI consultancy Quantum AI Partners metadata_rules: title_pattern: "{Primary Keyword} | Quantum AI Partners" - description_pattern: Engineering-grade {Topic} for {Audience} — AI strategy, - custom systems, and production hardening without the hype. + description_pattern: Engineering-grade {Topic} for {Audience} — AI strategy, custom systems, and production hardening without the hype. schema_rules: - Organization - ProfessionalService @@ -108,6 +162,102 @@ seo_contract: - thin_city_pages_before_national_strategy_is_approved - guaranteed_outcome_claim_pages wom_flags: [] +business_facts: + legal_name: Quantum AI Partners + tagline: Engineering-grade AI systems for business. + brand_positioning: An AI consultancy and delivery partner for strategy, custom AI/LLM systems, and production hardening — engineering-first, without hype. + primary_value: Take organizations from AI intent to working, evaluated, production-grade systems through a layered systems discipline. + competitive_angle: Layered-systems AI engineering — strategy, build, and production hardening as one continuous discipline, expressed without hype. + core_offer: AI strategy, custom AI and LLM systems, and production hardening. + offer_type: service + pricing_visibility: engagement_based + deliverables: + - strategy_roadmap + - working_prototype + - production_system + - evaluation_suite + - knowledge_transfer + decision_makers: + - cto + - vp_engineering + - head_of_product + - founder + pain_points: + - llm_adoption_uncertainty + - integration_risk + - talent_gap + - evaluation_gaps + - cost_uncertainty + - ai_hype_fatigue + - data_privacy_concerns + trust_requirements: + - engineering_depth + - honest_scoping + - security_first + - no_hype_language + - clear_pricing_signals + service_area_model: remote_first + service_lines: + - AI Strategy & Roadmaps + - Custom AI & LLM Systems + - AI Modernization & MLOps +conversion_authority: + primary_action: Book an Intro Call + secondary_actions: + - Email Us + - Explore Services + cta_library: + - Book an Intro Call + - Email Us + - Explore Services + - See the Approach +content_guardrails: + forbidden_claims: + - agi_claims + - fake_benchmarks + - guaranteed_roi + - hallucination_free_guarantees + - invented_case_studies + - invented_client_names + - performance_guarantees + - trusted_by_claims +semantic_provenance: + source_spec_version: 1.0.0 + compiler_version: 1.1.0 + runtime_authority_paths: + - assets + - audience + - authority + - build_intent + - client_vision + - content + - conversion + - design + - design_references + - geography + - identity + - market + - offer + - seo + gate_paths: + - authority + - compliance + - design + - validation + provenance_paths: + - authority + - content + - deployment + - design + - experiments + - future_outputs + - geography + - identity + - integrations + - market + - metadata + - notes + - validation assets: generation: enabled: true @@ -117,12 +267,9 @@ assets: build_intent: REDESIGN_IMPROVE client_vision: desired_outcomes: - - Position Quantum AI Partners as a distinctive, engineering-deep AI partner - — never a generic AI consultancy template. - - Convert visitors into intro-call and email inquiries through a clear, - low-friction path. - - Communicate layered-systems depth (strategy to build to production) - without hype. + - Position Quantum AI Partners as a distinctive, engineering-deep AI partner — never a generic AI consultancy template. + - Convert visitors into intro-call and email inquiries through a clear, low-friction path. + - Communicate layered-systems depth (strategy to build to production) without hype. brand_attributes: - distinctive - graphically_rich @@ -200,8 +347,7 @@ design_references: negative: [] - reference_id: baseten url: https://www.baseten.co/ - selection_reason: "Client likes: cool graphics; shows layers; layers apply to L9 - and Quantum AI Partners." + selection_reason: "Client likes: cool graphics; shows layers; layers apply to L9 and Quantum AI Partners." evidence_refs: - likes_dislikes_table_2026-09-01 principles: diff --git a/scripts/golden-safehaven/fixtures/build-fixtures.mjs b/scripts/golden-safehaven/fixtures/build-fixtures.mjs index 06e9a460..fe460a28 100644 --- a/scripts/golden-safehaven/fixtures/build-fixtures.mjs +++ b/scripts/golden-safehaven/fixtures/build-fixtures.mjs @@ -161,9 +161,9 @@ writeJson(path.join(ASSETS, "redesign-integrity-receipt.json"), { "release-receipt", "seo-baseline", "visual-qa", + "redesign-integrity-receipt", "release-receipt-finalizer", "handoff-emitter", - "redesign-integrity-receipt", "terminal-convergence", ], competitive_landscape: { @@ -807,9 +807,9 @@ const STAGES = [ "release-receipt", "seo-baseline", "visual-qa", + "redesign-integrity-receipt", "release-receipt-finalizer", "handoff-emitter", - "redesign-integrity-receipt", "terminal-convergence", ]; for (let i = 0; i < STAGES.length; i++) { diff --git a/scripts/normalize-spec.ts b/scripts/normalize-spec.ts index 6c3869c8..17e03a79 100644 --- a/scripts/normalize-spec.ts +++ b/scripts/normalize-spec.ts @@ -376,31 +376,77 @@ function carryStructuredAssets(ds: any, flat: DomainSpec): void { } } +/** + * Every committed source -> normalized IR pair. The default gate used to cover + * only the first, so the second rotted silently the moment the v1.1 compiler + * began emitting route semantics: an artifact nothing verifies is an artifact + * that drifts. Both are checked and regenerated together. + */ +const COMMITTED_SPECS: ReadonlyArray<{ in: string; out: string }> = [ + { + in: "examples/supplemental-insurance-pros/domain_spec.source.yaml", + out: "examples/supplemental-insurance-pros/domain_spec.normalized.yaml", + }, + { + in: "examples/quantum-ai-partners/domain_spec.source.yaml", + out: "examples/quantum-ai-partners/domain_spec.normalized.yaml", + }, +]; + +/** + * A source and its normalized output are one unit, so an override names either + * both sides or neither. Filling the missing half from a default let + * `--in ` write over a DIFFERENT client's committed artifact while + * looking entirely deliberate; a one-sided flag now resolves only against a + * committed pair, and an unrecognised path is an error rather than a guess. + */ +function resolveTargets(inArg?: string, outArg?: string): ReadonlyArray<{ in: string; out: string }> { + if (inArg === undefined && outArg === undefined) return COMMITTED_SPECS; + if (inArg !== undefined && outArg !== undefined) return [{ in: inArg, out: outArg }]; + const side = inArg !== undefined ? "in" : "out"; + const value = (inArg ?? outArg) as string; + const matches = COMMITTED_SPECS.filter((pair) => pair[side] === value); + if (matches.length !== 1) { + throw new Error( + `--${side} ${value} does not identify exactly one committed spec pair ` + + `(${matches.length} matched). Pass both --in and --out, or name a committed ` + + `--${side} path: ${COMMITTED_SPECS.map((pair) => pair[side]).join(", ")}`, + ); + } + return matches; +} + function main() { const args = process.argv.slice(2); const check = args.includes("--check"); - const inPath = getArg(args, "--in") ?? "examples/supplemental-insurance-pros/domain_spec.source.yaml"; - const outPath = getArg(args, "--out") ?? "examples/supplemental-insurance-pros/domain_spec.normalized.yaml"; - const flat = buildFlatSpec(parse(readFileSync(inPath, "utf-8"))); - validateDomainSpec(flat, `${inPath} (normalized)`); - if (check) { - const committed = parse(readFileSync(outPath, "utf-8")); - if (!deepEqual(flat, committed)) { - console.error(`normalize-spec --check FAILED: ${outPath} is stale.\nRegenerate with: tsx scripts/normalize-spec.ts`); - for (const key of Object.keys(flat)) { - if (!deepEqual((flat as any)[key], (committed as any)?.[key])) { - console.error(` first diff at key: ${key}`); - break; + const targets = resolveTargets(getArg(args, "--in"), getArg(args, "--out")); + for (const { in: inPath, out: outPath } of targets) { + const flat = buildFlatSpec(parse(readFileSync(inPath, "utf-8"))); + validateDomainSpec(flat, `${inPath} (normalized)`); + if (check) { + const committed = parse(readFileSync(outPath, "utf-8")); + if (!deepEqual(flat, committed)) { + console.error(`normalize-spec --check FAILED: ${outPath} is stale.\nRegenerate with: tsx scripts/normalize-spec.ts`); + for (const key of Object.keys(flat)) { + if (!deepEqual((flat as any)[key], (committed as any)?.[key])) { + console.error(` first diff at key: ${key}`); + break; + } } + process.exit(1); } - process.exit(1); + console.log(`normalize-spec --check OK: ${outPath} matches normalize(${inPath}).`); + continue; } - console.log(`normalize-spec --check OK: ${outPath} matches normalize(${inPath}).`); - return; + mkdirSync(dirname(outPath), { recursive: true }); + // lineWidth: 0 disables folding. The committed artifacts were generated + // unfolded while the writer kept the yaml package's 80-column default, so + // without this pin a regeneration rewraps an in-sync file by +76 bytes and + // the gate stays green through the churn — it compares parsed objects, not + // bytes. + writeFileSync(outPath, stringify(flat, { lineWidth: 0 }), "utf-8"); + console.log(`Wrote ${outPath} from ${inPath}.`); } - mkdirSync(dirname(outPath), { recursive: true }); - writeFileSync(outPath, stringify(flat), "utf-8"); - console.log(`Wrote ${outPath} from ${inPath}.`); } /** diff --git a/src/inngest/website-pipeline.ts b/src/inngest/website-pipeline.ts index 29821154..e5107fd6 100644 --- a/src/inngest/website-pipeline.ts +++ b/src/inngest/website-pipeline.ts @@ -91,6 +91,11 @@ export const websitePipeline = inngest.createFunction( mode, specPath: data.specPath, provision: shouldProvision, + // Without this the plan builder always saw buildIntent undefined, so a + // REDESIGN_IMPROVE spec ran the COPY topology on the durable path: no + // preflight, no competitive intelligence, no redesign authority chain, + // and no redesign-integrity-receipt gate at all. + buildIntent: ctx.buildIntent, }); compensation.register("release-evidence", async () => { diff --git a/src/pipeline/FactoryExecutionPlan.ts b/src/pipeline/FactoryExecutionPlan.ts index 45f2acab..0b962d67 100644 --- a/src/pipeline/FactoryExecutionPlan.ts +++ b/src/pipeline/FactoryExecutionPlan.ts @@ -305,14 +305,18 @@ export function buildFactoryExecutionPlan( stages.push(new ClientSourcePublishStage()); if (options.mode === "end-to-end") stages.push(new VercelDeployStage()); stages.push(new ReleaseReceiptStage()); - if (options.mode === "end-to-end") - stages.push( - new SEOBaselineStage(), - new VisualQAStage(), - new ReleaseReceiptFinalizerStage(), - new HandoffEmitterStage(), - ); + if (options.mode === "end-to-end") stages.push(new SEOBaselineStage(), new VisualQAStage()); + // The redesign integrity gate must veto BEFORE success is recorded and before + // anything leaves the process. ReleaseReceiptFinalizerStage writes + // status: "succeeded" and HandoffEmitterStage performs the external POST to + // SEO-Bot, so a gate placed after them can only reject a run that has already + // been published. It stays outside the end-to-end guard because + // REDESIGN_ADDED_MANDATORY makes redesign-integrity-receipt mandatory in every + // mode — folding it inside would make requireMandatoryConvergence throw on + // plan, local-proof and publish-proof redesign runs. if (redesign) stages.push(new RedesignIntegrityReceiptStage()); + if (options.mode === "end-to-end") + stages.push(new ReleaseReceiptFinalizerStage(), new HandoffEmitterStage()); stages.push( new TerminalConvergenceStage(options.mode, mandatory, REQUIRED_EVIDENCE[options.mode]), ); diff --git a/tests/unit/factory-execution-plan.test.ts b/tests/unit/factory-execution-plan.test.ts index 1ebbb26e..d6822192 100644 --- a/tests/unit/factory-execution-plan.test.ts +++ b/tests/unit/factory-execution-plan.test.ts @@ -134,6 +134,40 @@ test("REDESIGN preflight precedes competitive intelligence", () => { ); }); +test("redesign integrity gate runs before success finalization and handoff", () => { + const plan = buildFactoryExecutionPlan({ + mode: "end-to-end", + specPath: "fixtures/ci-test-spec.yaml", + buildIntent: "REDESIGN_IMPROVE", + }); + const names = plan.stages.map((stage) => stage.name); + const at = (name: string) => { + const index = names.indexOf(name); + assert.ok(index > -1, `${name} must be present in an end-to-end redesign plan`); + return index; + }; + // ReleaseReceiptFinalizerStage records status "succeeded" and + // HandoffEmitterStage performs the external POST. A gate after either can + // only reject a run that has already been published, so ordering here IS + // the guarantee — nothing else enforces it. + assert.ok( + at("visual-qa") < at("redesign-integrity-receipt"), + "redesign-integrity-receipt reads ctx.qualityEvidence.visualQa and must follow visual-qa", + ); + assert.ok( + at("redesign-integrity-receipt") < at("release-receipt-finalizer"), + "an invalid redesign must be rejected before the release is recorded as succeeded", + ); + assert.ok( + at("release-receipt-finalizer") < at("handoff-emitter"), + "handoff follows finalization", + ); + assert.ok( + at("handoff-emitter") < at("terminal-convergence"), + "terminal-convergence stays last", + ); +}); + test("COPY intent (legacy default) keeps the original stage topology", () => { const plan = buildFactoryExecutionPlan({ mode: "local-proof", diff --git a/tests/unit/normalize-spec.test.ts b/tests/unit/normalize-spec.test.ts index b96485e5..932603d2 100644 --- a/tests/unit/normalize-spec.test.ts +++ b/tests/unit/normalize-spec.test.ts @@ -294,3 +294,62 @@ test("importing the normalizer does not run its CLI writer", () => { ); assert.equal(readFileSync(outPath, "utf-8"), bodyBefore); }); + +const SUPPLEMENTAL_OUT = "examples/supplemental-insurance-pros/domain_spec.normalized.yaml"; +const QUANTUM_SOURCE = "examples/quantum-ai-partners/domain_spec.source.yaml"; +const QUANTUM_OUT = "examples/quantum-ai-partners/domain_spec.normalized.yaml"; + +function runCli(args: string[]) { + return spawnSync(process.execPath, ["--import", "tsx", "scripts/normalize-spec.ts", ...args], { + encoding: "utf-8", + }); +} + +test("a one-sided --in resolves its own committed pair, never another client's output", () => { + // The defect this guards: filling the missing half from COMMITTED_SPECS[0] + // paired one client's source with a different client's artifact, so + // `--in ` compiled quantum and wrote it over supplemental's + // committed IR while looking entirely deliberate. + const bodyBefore = readFileSync(SUPPLEMENTAL_OUT, "utf-8"); + const mtimeBefore = statSync(SUPPLEMENTAL_OUT).mtimeMs; + + const result = runCli(["--check", "--in", QUANTUM_SOURCE]); + + assert.equal(result.status, 0, result.stderr); + assert.match( + result.stdout + result.stderr, + new RegExp(QUANTUM_OUT.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")), + "a one-sided --in must be judged against its own pair's output", + ); + assert.equal(readFileSync(SUPPLEMENTAL_OUT, "utf-8"), bodyBefore); + assert.equal(statSync(SUPPLEMENTAL_OUT).mtimeMs, mtimeBefore); +}); + +test("a one-sided --out resolves its own committed pair", () => { + const result = runCli(["--check", "--out", QUANTUM_OUT]); + assert.equal(result.status, 0, result.stderr); + assert.match( + result.stdout, + new RegExp(QUANTUM_SOURCE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")), + "a one-sided --out must compile its own pair's source", + ); +}); + +test("a one-sided override naming no committed pair fails instead of guessing", () => { + const result = runCli(["--check", "--in", "examples/does-not-exist/domain_spec.source.yaml"]); + assert.notEqual(result.status, 0, "an unrecognised one-sided path must not silently pick a pair"); + assert.match(result.stderr, /does not identify exactly one committed spec pair/); +}); + +test("the default gate covers every committed source-to-normalized pair", () => { + // Preservation obligation: the check must not narrow back to one client. + const result = runCli(["--check"]); + assert.equal(result.status, 0, result.stderr); + for (const outPath of [SUPPLEMENTAL_OUT, QUANTUM_OUT]) { + assert.match( + result.stdout, + new RegExp(outPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")), + `${outPath} must be covered by the default check`, + ); + } +}); diff --git a/validation/validation_report.yaml b/validation/validation_report.yaml deleted file mode 100644 index fe05df04..00000000 --- a/validation/validation_report.yaml +++ /dev/null @@ -1,433 +0,0 @@ -run_metadata: - run_id: 8a3153ad-c205-4d63-9dac-38301fc4d4c3 - report_schema_version: 1.0.0 - started_at: 2026-09-02T20:23:41.177Z - ended_at: 2026-09-02T20:23:41.443Z - duration: 266 - last_completed_stage: audit_report_generation -execution_context: - target_roots: - - /Users/ib-mac/.l9/website-bot-worktrees/replay-launch-env-20260902T012107Z - source_revision: efc53128be341a1bddb1178839c7265dd61eff35 - running_revision: null - target_environment: local - environment_type: local - active_identity: ib718@icloud.com - preflight_commands: - - node -e "require('node:fs').accessSync('astro_template/package.json')" - e2e_commands: - - npm --prefix astro_template run verify:rollback - test_runner: node:test - test_runner_version: v22.15.0 - configuration_sources: &a1 - - package.json - - tsconfig.json - - .env.example - - config/launch-env.required.yaml - - .github/workflows/ci.yml - - Makefile - - justfile - required_services: - - postgresql - - sqlite - target_endpoints: - - http://localhost:4321 - - http://localhost:3000 - required_dependencies: - - "@quantum-l9/bot-interop" - - "@quantum-l9/graphiti-memory-client" - - "@quantum-l9/infisical-config" - - "@quantum-l9/llm-router" - - better-sqlite3 - - drizzle-orm - - inngest - - pg - - pino - - undici - - yaml - - "@types/better-sqlite3" - - "@types/node" - - "@types/pg" - - pino-pretty - - playwright - - tsx - - typescript - required_credentials: - - NODE_AUTH_TOKEN - - PERPLEXITY_API_KEY - - OPENROUTER_API_KEY - - CLIENT_ID - - MONTHLY_BUDGET_PER_CLIENT - - WEEKLY_BUDGET_TARGET - - WEEKLY_BUDGET_HARD_CEILING - - LLM_PROVIDER_TIMEOUT_MS - - SITE_URL - - SITE_OUTPUT_DIR - - SITE_BUILD_TIMEOUT_MS - - SITE_BUILD_IGNORE_SCRIPTS - - ASTRO_TELEMETRY_DISABLED - - CLIENT_GITHUB_REPO - - CLIENT_GITHUB_REPO_ID - - CLIENT_SOURCE_BRANCH - - GITHUB_SITE_TOKEN - - VERCEL_TOKEN - - VERCEL_TEAM_ID - - VERCEL_TARGET - - WEBSITE_BOT_ALLOW_PRODUCTION - - VERCEL_POLL_INTERVAL_MS - - VERCEL_MAX_POLLS - - CLIENT_VERCEL_PROJECT_ID - - CLIENT_VERCEL_DEPLOY_HOOK - - PUBLIC_POSTHOG_KEY - - POSTHOG_HOST - - POSTHOG_PROJECT_ID - - POSTHOG_PERSONAL_API_KEY - - DATAFORSEO_LOGIN - - DATAFORSEO_PASSWORD - - SEO_BOT_URL - - SEO_BOT_API_KEY - - PROJECT_LICENSE - - LICENSE_CHOICE_REQUIRED - - SUPPORT_CONTACT_EMAIL - - SUPPORT_CONTACT_URL - - SECURITY_CONTACT_EMAIL - - SECURITY_DISCLOSURE_URL - - PUBLIC_SITE_URL - - PRODUCTION_DOMAIN - - DOMAIN_VERIFICATION_REQUIRED - - FORM_PROVIDER - - FORM_ENDPOINT_URL - - FORM_WEBHOOK_SECRET - - LEAD_NOTIFICATION_EMAIL - - ANALYTICS_PROVIDER - - ANALYTICS_MEASUREMENT_ID - - ANALYTICS_CONVERSION_EVENT - - ANALYTICS_THANK_YOU_EVENT - - LEGAL_DISCLAIMER_APPROVED - - LEGAL_DISCLAIMER_VERSION - - LEGAL_REVIEW_OWNER - - LICENSE_DISPLAY_REQUIRED - - PROFESSIONAL_LICENSE_NUMBER - - PROFESSIONAL_LICENSE_STATE - - PROFESSIONAL_LICENSE_TYPE - - CRM_PROVIDER - - CRM_API_BASE_URL - - CRM_CLIENT_ID - - CRM_CLIENT_SECRET - - CRM_API_TOKEN - - CRM_TEST_MODE - - GITHUB_PROVISION_TOKEN - - SEO_BOT_SITE_GITHUB_TOKEN - - SEO_BOT_SITE_VERCEL_DEPLOY_HOOK - - L9_MEMORY_MODE - - L9_MEMORY_URL - - L9_MEMORY_TOKEN - - L9_MEMORY_TOKEN_BUDGET - - L9_MEMORY_MAX_RECORDS - - GEMINI_API_KEY - - IMAGE_GENERATION_MODEL - - IMAGE_GENERATION_BUDGET_USD - evidence_root: build/evidence -authority_sources: - - source: package.json - revision_or_version: efc53128be341a1bddb1178839c7265dd61eff35 - applicable_scope: execution_configuration - precedence: 1 - verification_status: verified - - source: tsconfig.json - revision_or_version: efc53128be341a1bddb1178839c7265dd61eff35 - applicable_scope: execution_configuration - precedence: 2 - verification_status: verified - - source: .env.example - revision_or_version: current - applicable_scope: execution_configuration - precedence: 3 - verification_status: verified - - source: config/launch-env.required.yaml - revision_or_version: efc53128be341a1bddb1178839c7265dd61eff35 - applicable_scope: execution_configuration - precedence: 4 - verification_status: verified - - source: .github/workflows/ci.yml - revision_or_version: efc53128be341a1bddb1178839c7265dd61eff35 - applicable_scope: execution_configuration - precedence: 5 - verification_status: verified - - source: Makefile - revision_or_version: efc53128be341a1bddb1178839c7265dd61eff35 - applicable_scope: execution_configuration - precedence: 6 - verification_status: verified - - source: justfile - revision_or_version: current - applicable_scope: execution_configuration - precedence: 7 - verification_status: verified -discovery_inventory: - preflight_checks: &a2 - - check_id: astro-template-present - check_name: Astro template package present - blocking: true - command: node -e "require('node:fs').accessSync('astro_template/package.json')" - working_directory: /Users/ib-mac/.l9/website-bot-worktrees/replay-launch-env-20260902T012107Z - status: Passed - exit_code: 0 - termination_signal: null - started_at: 2026-09-02T20:23:41.235Z - ended_at: 2026-09-02T20:23:41.263Z - duration: 28 - primary_failure_classification: null - contributing_causes: [] - root_cause_group: null - evidence_references: - - preflight_astro-template-present_stdout - - preflight_astro-template-present_stderr - - preflight_astro-template-present_execution_trace - e2e_suites: - - Astro Template Site Validation - required_e2e_tests: &a3 - - suite_id: site-template - suite_name: Astro Template Site Validation - test_id: verify-rollback - test_name: rollback site-template validation - attempt: 1 - command_or_invocation: npm --prefix astro_template run verify:rollback - status: Passed - started_at: 2026-09-02T20:23:41.265Z - ended_at: 2026-09-02T20:23:41.440Z - duration: 175 - assertion_or_error: null - exit_code_or_runner_result: 0 - primary_failure_classification: null - contributing_causes: [] - root_cause_group: null - evidence_references: - - e2e_verify-rollback_stdout - - e2e_verify-rollback_stderr - - e2e_verify-rollback_execution_trace - dynamic_inventory_items: - - service-dependency:postgresql - - service-dependency:sqlite - - credential-dependent:NODE_AUTH_TOKEN - - credential-dependent:PERPLEXITY_API_KEY - - credential-dependent:OPENROUTER_API_KEY - - credential-dependent:CLIENT_ID - - credential-dependent:MONTHLY_BUDGET_PER_CLIENT - - credential-dependent:WEEKLY_BUDGET_TARGET - - credential-dependent:WEEKLY_BUDGET_HARD_CEILING - - credential-dependent:LLM_PROVIDER_TIMEOUT_MS - - credential-dependent:SITE_URL - - credential-dependent:SITE_OUTPUT_DIR - - credential-dependent:SITE_BUILD_TIMEOUT_MS - - credential-dependent:SITE_BUILD_IGNORE_SCRIPTS - - credential-dependent:ASTRO_TELEMETRY_DISABLED - - credential-dependent:CLIENT_GITHUB_REPO - - credential-dependent:CLIENT_GITHUB_REPO_ID - - credential-dependent:CLIENT_SOURCE_BRANCH - - credential-dependent:GITHUB_SITE_TOKEN - - credential-dependent:VERCEL_TOKEN - - credential-dependent:VERCEL_TEAM_ID - - credential-dependent:VERCEL_TARGET - - credential-dependent:WEBSITE_BOT_ALLOW_PRODUCTION - - credential-dependent:VERCEL_POLL_INTERVAL_MS - - credential-dependent:VERCEL_MAX_POLLS - - credential-dependent:CLIENT_VERCEL_PROJECT_ID - - credential-dependent:CLIENT_VERCEL_DEPLOY_HOOK - - credential-dependent:PUBLIC_POSTHOG_KEY - - credential-dependent:POSTHOG_HOST - - credential-dependent:POSTHOG_PROJECT_ID - - credential-dependent:POSTHOG_PERSONAL_API_KEY - - credential-dependent:DATAFORSEO_LOGIN - - credential-dependent:DATAFORSEO_PASSWORD - - credential-dependent:SEO_BOT_URL - - credential-dependent:SEO_BOT_API_KEY - - credential-dependent:PROJECT_LICENSE - - credential-dependent:LICENSE_CHOICE_REQUIRED - - credential-dependent:SUPPORT_CONTACT_EMAIL - - credential-dependent:SUPPORT_CONTACT_URL - - credential-dependent:SECURITY_CONTACT_EMAIL - - credential-dependent:SECURITY_DISCLOSURE_URL - - credential-dependent:PUBLIC_SITE_URL - - credential-dependent:PRODUCTION_DOMAIN - - credential-dependent:DOMAIN_VERIFICATION_REQUIRED - - credential-dependent:FORM_PROVIDER - - credential-dependent:FORM_ENDPOINT_URL - - credential-dependent:FORM_WEBHOOK_SECRET - - credential-dependent:LEAD_NOTIFICATION_EMAIL - - credential-dependent:ANALYTICS_PROVIDER - - credential-dependent:ANALYTICS_MEASUREMENT_ID - - credential-dependent:ANALYTICS_CONVERSION_EVENT - - credential-dependent:ANALYTICS_THANK_YOU_EVENT - - credential-dependent:LEGAL_DISCLAIMER_APPROVED - - credential-dependent:LEGAL_DISCLAIMER_VERSION - - credential-dependent:LEGAL_REVIEW_OWNER - - credential-dependent:LICENSE_DISPLAY_REQUIRED - - credential-dependent:PROFESSIONAL_LICENSE_NUMBER - - credential-dependent:PROFESSIONAL_LICENSE_STATE - - credential-dependent:PROFESSIONAL_LICENSE_TYPE - - credential-dependent:CRM_PROVIDER - - credential-dependent:CRM_API_BASE_URL - - credential-dependent:CRM_CLIENT_ID - - credential-dependent:CRM_CLIENT_SECRET - - credential-dependent:CRM_API_TOKEN - - credential-dependent:CRM_TEST_MODE - - credential-dependent:GITHUB_PROVISION_TOKEN - - credential-dependent:SEO_BOT_SITE_GITHUB_TOKEN - - credential-dependent:SEO_BOT_SITE_VERCEL_DEPLOY_HOOK - - credential-dependent:L9_MEMORY_MODE - - credential-dependent:L9_MEMORY_URL - - credential-dependent:L9_MEMORY_TOKEN - - credential-dependent:L9_MEMORY_TOKEN_BUDGET - - credential-dependent:L9_MEMORY_MAX_RECORDS - - credential-dependent:GEMINI_API_KEY - - credential-dependent:IMAGE_GENERATION_MODEL - - credential-dependent:IMAGE_GENERATION_BUDGET_USD - authoritative_skips: [] - inventory_sources: *a1 - inventory_status: complete -preflight_summary: - discovered: 1 - executable: 1 - executed: 1 - passed: 1 - failed: 0 - errors: 0 - timeouts: 0 - blocked: 0 - authoritatively_skipped: 0 - not_executed: 0 - unknown: 0 - blocking_total: 1 - blocking_passed: 1 - gate_status: Passed -preflight_results: *a2 -preflight_gate: - status: Passed - blocking_failures: [] - blocking_unknowns: [] - e2e_authorized: true - decision_evidence: - - preflight_astro-template-present_result -e2e_summary: - discovered_suites: 1 - discovered_required_tests: 1 - executed_unique_tests: 1 - execution_attempts: 1 - passed: 1 - failed: 0 - errors: 0 - timeouts: 0 - blocked_by_preflight_gate: 0 - blocked_by_authoritative_fail_fast: 0 - blocked: 0 - not_executed: 0 - authoritatively_skipped: 0 - unknown: 0 - runner_crashes: 0 - gate_status: Passed -e2e_results: *a3 -coverage_reconciliation: - preflight_discovered_total: 1 - preflight_accounted_total: 1 - preflight_reconciled: true - e2e_required_discovered_total: 1 - e2e_required_accounted_total: 1 - e2e_reconciled: true - dynamic_inventory_reconciliation: complete - retry_accounting: complete - unaccounted_items: [] - status: complete -root_cause_groups: [] -defects: [] -regressions: [] -unknowns: [] -evidence_manifest: - - evidence_id: preflight_astro-template-present - evidence_type: command_execution - file_path: preflight_astro-template-present.json - checksum: 448038322ae63f76cfbd5a49452bbe150fdad3ec6bc43051766fc6d30eef3229 - file_size: 597 - created_at: 2026-09-02T20:23:41.264Z - integrity_validated: true - - evidence_id: e2e_verify-rollback_attempt_1 - evidence_type: command_execution - file_path: e2e_verify-rollback_attempt_1.json - checksum: 0b7fc2597a3ce6658cd428a261ab72e6b834a6de3b67bc1eb3a2294eeb311a1f - file_size: 592 - created_at: 2026-09-02T20:23:41.441Z - integrity_validated: true -validation_gates: - execution_context_resolved: - status: Passed - evidence_references: - - execution_context_validation_8a3153ad-c205-4d63-9dac-38301fc4d4c3 - authoritative_inventory_resolved: - status: Passed - evidence_references: - - inventory_validation_8a3153ad-c205-4d63-9dac-38301fc4d4c3 - preparation_passed: - status: Passed - evidence_references: - - preparation_validation_8a3153ad-c205-4d63-9dac-38301fc4d4c3 - preflight_inventory_complete: - status: Passed - evidence_references: [] - preflight_passed: - status: Passed - evidence_references: - - preflight_gate_evaluation_6838455d-8a03-4bda-a131-7a4803e0de1c - - preflight_astro-template-present_result - e2e_gate_enforced: - status: Passed - evidence_references: [] - e2e_inventory_complete: - status: Passed - evidence_references: [] - e2e_tests_passed: - status: Passed - evidence_references: - - e2e_gate_evaluation_8456a3b2-ed7f-43d4-8873-415e25ee3ed9 - - e2e_verify-rollback_result - no_unauthorized_skips: - status: Passed - evidence_references: [] - no_result_replacement: - status: Passed - evidence_references: [] - evidence_complete: - status: Passed - evidence_references: - - evidence_integrity_8a3153ad-c205-4d63-9dac-38301fc4d4c3 - failure_classification_complete: - status: Passed - evidence_references: [] - regression_evidence_valid: - status: Passed - evidence_references: [] - coverage_reconciled: - status: Passed - evidence_references: [] - target_unchanged: - status: Passed - evidence_references: [] - report_schema_valid: - status: Passed - evidence_references: [] - overall_validation_run: - status: Passed - evidence_references: [] -final_verdict: - status: PASS - preflight_status: Passed - e2e_status: Passed - coverage_status: Passed - evidence_status: Passed - required_failure_count: 0 - blocking_defect_ids: [] - unknown_count: 0 - verdict_reason: All required validation gates passed and no test failures detected -minimum_safe_next_action: - action: NoActionRequired - blocker_or_failure: None - expected_evidence: Validation completed successfully