@skyramp/testbot-core 0.13.0-v3.74 → 0.13.0-v3.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/VERSION.json CHANGED
@@ -1 +1 @@
1
- {"version":"0.13.0-v3.74","commit":"1c8a31e95ef636c400f909cb04f60eebbe351ff2"}
1
+ {"version":"0.13.0-v3.75","commit":"b0d053dd6a486da7bceca61b24b84e84fb0b587e"}
package/dist/main.js CHANGED
@@ -415,7 +415,7 @@ ${Het(e)}}`}case"ZodArray":{let i=n.element;return`[ ${YP(i,e,r)}, \u2026 ]`}cas
415
415
  # Written by ${r}: the recorded command, which needed a shell to run.
416
416
  set -euo pipefail
417
417
  ${n}
418
- `,{mode:493})}catch{return}return`bash ${ba(e)}`}}function ba(t){return`'${t.split("'").join("'\\''")}'`}var au=$(require("fs")),oo=$(require("path"));var Cnr=oo.join(".skyramp","workspace.yml"),rtt=new Set(["playwright","cypress","selenium"]);function Vg(t){return typeof t=="string"&&t.trim()?t.trim():void 0}function dl(t){let e=oo.join(t,Cnr);if(!au.existsSync(e))return[];let r;try{r=Ig(au.readFileSync(e,"utf-8"))}catch{return[]}let n=r?.services;if(!Array.isArray(n))return[];let s=[];for(let i of n){if(typeof i!="object"||i===null)continue;let o=i,a=o.api??{},c=Vg(o.serviceName);c&&s.push({serviceName:c,language:Vg(o.language),framework:Vg(o.framework),testDirectory:Vg(o.testDirectory),schemaPath:Vg(a.schemaPath),authType:Vg(a.authType),authHeader:Vg(a.authHeader),baseUrl:Vg(a.baseUrl)})}return s}function JP(t){return t.filter(e=>!e.framework||!rtt.has(e.framework.toLowerCase()))}function ntt(t){return[...new Set(JP(t).map(e=>e.testDirectory?.replace(/\/+$/,"")).filter(e=>!!e))]}function stt(t){return[...new Set(t.filter(e=>KP(e.framework)).map(e=>e.testDirectory?.replace(/\/+$/,"")).filter(e=>!!e))]}function KP(t){return!!(t&&rtt.has(t.toLowerCase()))}var Inr={golang:"go",py:"python",py3:"python",python3:"python",ts:"typescript",js:"javascript","c++":"cpp",cplusplus:"cpp",cxx:"cpp",node:"javascript",nodejs:"javascript",rb:"ruby",cs:"csharp","c#":"csharp"};function ic(t){let e=t?.trim().toLowerCase();if(e)return Inr[e]??e}var itt={py:"python",go:"go",java:"java",kt:"kotlin",rb:"ruby",cs:"csharp",ts:"typescript",tsx:"typescript",js:"javascript",jsx:"javascript",mjs:"javascript",cjs:"javascript",kts:"kotlin",rs:"rust",php:"php",scala:"scala",swift:"swift",ex:"elixir",exs:"elixir",dart:"dart",c:"c",h:"c",cpp:"cpp",cc:"cpp",cxx:"cpp",hpp:"cpp",hh:"cpp",groovy:"groovy"},Rnr=new Set(["feature"]);function ott(t){let e=t.lastIndexOf(".");return e>=0&&Rnr.has(t.slice(e+1).toLowerCase())}var vnr=new Set(Object.values(itt));function att(t){let e=ic(t);return e!==void 0&&vnr.has(e)}function ME(t){let e=t.lastIndexOf(".");if(!(e<0))return itt[t.slice(e+1).toLowerCase()]}function Nde(t){return[...new Set(JP(t).map(e=>ic(e.language)).filter(e=>!!e))]}function CI(t,e=[]){let r=Nde(dl(t));return r.length?r:[...new Set(e.map(n=>ic(n)).filter(n=>!!n))]}function ctt(t,e,r=[]){let n=CI(t,r);if(n.length===0)return!0;let s=ic(e);return s!==void 0&&n.includes(s)}var Fz=(s=>(s.Python="python",s.Node="node",s.Jvm="jvm",s.Go="go",s))(Fz||{}),Nnr={python:"python",typescript:"node",javascript:"node",java:"jvm",kotlin:"jvm",go:"go"};function Wg(t){let e=ic(t);return e?Nnr[e]:void 0}var ltt={python:["pyproject.toml","requirements.txt","setup.py","setup.cfg","Pipfile"],node:["package.json"],jvm:["pom.xml","build.gradle","build.gradle.kts"],go:["go.mod"]},Tnr=new Set(["node_modules",".git",".venv","venv","dist","build","target","vendor",".skyramp","__pycache__"]),Bnr=3;function Pnr(t,e){let r=[],n=(s,i)=>{let o=oo.join(t,s);if(ltt[e].some(c=>au.existsSync(oo.join(o,c)))&&r.push(s),i>=Bnr)return;let a;try{a=au.readdirSync(o,{withFileTypes:!0})}catch{return}for(let c of a)c.isDirectory()&&!Tnr.has(c.name)&&!c.name.startsWith(".")&&n(s==="."?c.name:oo.join(s,c.name),i+1)};return n(".",0),r}function knr(t,e){return au.existsSync(oo.join(t,e,"tsconfig.json"))?"typescript":"javascript"}function _nr(t,e,r){let n=oo.normalize(e??".");for(;;){if(ltt[r].some(s=>au.existsSync(oo.join(t,n,s))))return n;if(n==="."||n===oo.sep||n==="")return".";n=oo.dirname(n)}}function Dnr(t,e){let r;try{r=au.readdirSync(oo.join(t,e))}catch{return!1}if(r.some(n=>/^playwright\.config\.[cm]?[jt]s$/.test(n)||/^cypress\.config\.[cm]?[jt]s$/.test(n)))return!0;for(let n of["package.json","pyproject.toml","requirements.txt"])try{if(/playwright|cypress|selenium/i.test(au.readFileSync(oo.join(t,e,n),"utf-8")))return!0}catch{}return!1}function XP(t,e){let r=dl(t),n=e==="ui"?r.filter(o=>KP(o.framework)):JP(r),s=[];for(let o of n){let a=ic(o.language),c=Wg(a);a&&s.push({language:a,dir:c?_nr(t,o.testDirectory,c):"."})}if(s.length)return ttt(s);let i=[];for(let o of Object.values(Fz))for(let a of Pnr(t,o)){if(e==="ui"&&!Dnr(t,a))continue;let c=o==="node"?knr(t,a):o==="jvm"?"java":o;i.push({language:c,dir:a})}return ttt(i)}function ttt(t){let e=new Set;return t.filter(r=>{let n=`${r.language}::${r.dir}`;return e.has(n)?!1:(e.add(n),!0)})}function Uz(t){try{return new URL(t).hostname.replace(/^\[|\]$/g,"").toLowerCase()||void 0}catch{return}}function Tde(t){if(!t)return!1;let e=t.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="::1"||e==="0.0.0.0"||/^127(\.\d{1,3}){3}$/.test(e)}function Bde(t){let e=new Set;for(let r of dl(t)){let n=r.baseUrl&&Uz(r.baseUrl);n&&e.add(n)}return e}function $z(t,e,r=Bde(e)){let n;try{n=new URL(t).protocol}catch{return!1}if(n!=="http:"&&n!=="https:")return!1;let s=Uz(t);return s?Tde(s)||r.has(s):!1}var Cf=(s=>(s.Clean="clean",s.RecipeDrift="recipe-drift",s.ChangeBrokeBringup="change-broke-bringup",s.BringupFailed="bringup-failed",s))(Cf||{}),Yg=E.string().trim().min(1),Mnr=E.object({url:E.string().optional().describe("the URL probed, if the check is an HTTP request"),command:E.string().optional().describe("the command run, if the check is a script \u2014 preferred when auth is needed"),headers:E.record(E.string()).optional(),status:E.union([E.number(),E.string()]).optional().describe("expected HTTP status for a url check (default 200)"),output:Yg.describe("what the check returned, VERBATIM \u2014 the bytes, nothing appended; this gate RE-RUNS the check")}),ZP=E.object({schemaVersion:E.literal(1),baseUrls:E.record(E.string()).optional().describe("service \u2192 base URL of the running app; omit on a failed bring-up, never invent one"),health:Mnr.optional(),teardown:Yg.describe("command that tears the SUT down"),dependencies:E.record(E.boolean()).optional().describe("EVERY backing service: true = really deployed, false = mocked; REQUIRED when the app came up"),outcome:E.nativeEnum(Cf).describe("clean | recipe-drift (you corrected the recipe) | change-broke-bringup (the PR broke it) | bringup-failed (environment, not the PR)"),recipeFixes:E.array(E.string()).optional().describe("required when outcome is recipe-drift: what was corrected"),bringupError:E.object({command:Yg,output:Yg}).optional().describe("required when bring-up failed: the exact failing command and what it printed"),suspectFiles:E.array(E.string()).optional().describe("required for change-broke-bringup: files THIS PR changed that the failure points at, relative to your working directory (a file in another checkout of the run: its absolute path)"),seeded:E.boolean(),startedAt:Yg.describe("ISO timestamp"),revisions:E.array(E.object({component:Yg.describe("a shared component listed above"),url:Yg.describe("the URL on the component's own origin (scheme, host and port) that answers with its deployed commit"),output:Yg.describe("what the URL returned, VERBATIM; this gate FETCHES each url")})).optional().describe("only when shared components are listed above: one check per component whose deployed commit you found")});function Pde(t){let e=[],r=s=>!!s&&typeof s=="object"&&!Array.isArray(s);return t.outcome!=="change-broke-bringup"&&t.outcome!=="bringup-failed"?(!r(t.baseUrls)||Object.keys(t.baseUrls).length===0?e.push("baseUrls must be a non-empty object of service \u2192 url"):Object.values(t.baseUrls).every(s=>typeof s=="string"&&s.trim())||e.push("every baseUrls value must be a non-empty url string"),r(t.health)?!(typeof t.health.url=="string"&&t.health.url.trim())&&!(typeof t.health.command=="string"&&t.health.command.trim())&&e.push("health must record a url or a command (what you actually ran)"):e.push("health must be an object"),(!r(t.dependencies)||Object.keys(t.dependencies).length===0)&&e.push("dependencies must be a non-empty object of name \u2192 boolean (real vs mocked) when the SUT came up \u2014 account for every backing service so a mocked one can't be hidden behind a green run")):(r(t.bringupError)||e.push(`outcome "${String(t.outcome)}" requires bringupError { command, output } \u2014 the exact failing bring-up command and what it printed`),t.outcome==="change-broke-bringup"&&!(Array.isArray(t.suspectFiles)&&t.suspectFiles.length>0&&t.suspectFiles.every(s=>typeof s=="string"&&s.trim()))&&e.push("change-broke-bringup requires non-empty suspectFiles[] \u2014 the changed file(s) the failure points at; if you cannot point at a file this PR changed, the outcome is bringup-failed (environment/harness), not the PR's fault")),t.outcome==="recipe-drift"&&!(Array.isArray(t.recipeFixes)&&t.recipeFixes.length>0)&&e.push("recipe-drift outcome requires a non-empty recipeFixes[] describing what was corrected"),e}var II=(r=>(r.Full="full",r.Static="static",r))(II||{}),Ep=(n=>(n.Contract="contract",n.Integration="integration",n.Ui="ui",n))(Ep||{}),ek=(i=>(i.OwnSurface="own_surface",i.StateReadBack="state_read_back",i.Referential="referential",i.Lifecycle="lifecycle",i.Boundaries="boundaries",i))(ek||{}),OE=(s=>(s.Update="update",s.Regenerate="regenerate",s.Delete="delete",s.Verify="verify",s))(OE||{}),tk=(l=>(l.Equals="equals",l.NotEquals="not_equals",l.GreaterThan="greater_than",l.LessThan="less_than",l.Contains="contains",l.NotContains="not_contains",l.Matches="matches",l.Absent="absent",l.Present="present",l))(tk||{}),qz=["absent","present"],oc=E.string().trim().min(1),Onr=E.object({subject:oc.describe('what the test READS: a response field path, the literal "status", or the on-screen text for a ui case \u2014 the FINAL read in a multi-step case'),comparator:E.nativeEnum(tk),value:E.union([E.string(),E.number(),E.boolean(),E.null()]).optional().describe("the ONE value a broken build would not produce; OMIT for absent/present")}),Qnr=E.object({test:oc.describe("existing test path, relative to its repository"),repository:oc.optional().describe("owner/repo the test lives in, when the run has several checkouts; omit for the working checkout"),action:E.nativeEnum(OE),evidence:oc.describe("why \u2014 drift vs the diff, or a finding"),covers_behaviors:E.array(E.string()).optional().describe("analyze behavior ids this maintenance covers")}),Lnr=E.object({surface:oc.describe("a surface from the list, copied verbatim"),axis:E.nativeEnum(ek)}),Fnr=E.object({id:oc.describe("short-slug, unique across generate[]"),type:E.nativeEnum(Ep),target:oc.describe('"METHOD /path", or a business-flow name'),from_finding:E.string().optional().describe("analyze finding id this case catches"),from_behavior:E.string().optional().describe("analyze behavior id this case pins"),derived_from:Lnr.optional().describe("the surface \xD7 axis this case pins when no analyze behavior or finding names it \u2014 one of the three is required"),rationale:oc.describe("why this test matters"),expected_observable:oc.describe("one sentence for a human: what a catching test asserts, and what a broken build does instead"),expected:Onr.describe("the same intent AS DATA \u2014 see the rules below"),seededPrecondition:oc.optional().describe("seeded non-initial state + how to reach it; only when a seeded-state transition applies"),verifiable:E.boolean().describe("true only when a live SUT could confirm this test (full mode)")}),Unr=E.object({covered:E.array(E.string()).optional(),abstain:E.string().optional()}).superRefine((t,e)=>{let r=Array.isArray(t.covered),n=typeof t.abstain=="string";if(r===n)return void e.addIssue({code:E.ZodIssueCode.custom,message:"must have exactly one of covered[] or abstain"});r&&t.covered.length===0&&e.addIssue({code:E.ZodIssueCode.custom,path:["covered"],message:"must list at least one id (else abstain)"}),n&&!t.abstain.trim()&&e.addIssue({code:E.ZodIssueCode.custom,path:["abstain"],message:"must give a reason"})}).describe('{ "covered": [ids] } OR { "abstain": "reason" } \u2014 exactly one'),$nr=E.object({surface:oc.describe("a surface from the list, copied verbatim"),axes:E.object(Object.fromEntries(Object.values(ek).map(t=>[t,Unr])))}),rk=E.object({schemaVersion:E.literal(1),mode:E.nativeEnum(II),maintenance:E.array(Qnr),generate:E.array(Fnr),surfaces:E.array($nr).describe("one entry per changed surface in the list \u2014 none missing, none invented"),budget:E.object({total:E.number().describe("case count"),rationale:oc}),summary:oc.describe("one paragraph")});function Hz(t,e,r){let n=s=>{if(!s||!Array.isArray(s.covered))return s;let i=s.covered.filter(o=>!e.has(o));return i.length>0?{covered:i}:{abstain:`its only case(s) were ${r}: ${s.covered.join(", ")}`}};return t.map(s=>({...s,axes:Object.fromEntries(Object.entries(s.axes??{}).map(([i,o])=>[i,n(o)]))}))}function utt(t){let e=[],r=new Set;if(Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n?.id;typeof i=="string"&&(r.has(i)&&e.push(`generate[${s}].id "${i}" is duplicated`),r.add(i))}),Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n;!i.from_finding&&!i.from_behavior&&!i.derived_from&&e.push(`generate[${s}] carries none of from_behavior, from_finding or derived_from \u2014 say what obligation it pins`)}),Array.isArray(t.surfaces)){let n=new Set;t.surfaces.forEach((s,i)=>{let o=s;if(typeof o.surface=="string"){let a=o.surface.trim().toLowerCase();n.has(a)&&e.push(`surfaces[${i}] "${o.surface}" is listed twice`),n.add(a)}for(let[a,c]of Object.entries(o.axes??{})){let l=c?.covered;if(Array.isArray(l))for(let u of l)(typeof u!="string"||!r.has(u))&&e.push(`surfaces[${i}].axes.${a}.covered references unknown generate id ${JSON.stringify(u)}`)}})}return e}var RI=(r=>(r.Ready="ready",r.Blocked="blocked",r))(RI||{}),as=E.string().trim().min(1),qnr=E.object({action:E.enum(["start","run","wait"]),text:as,source:E.enum(["file","notes","testbot"]).describe("file: a file in the repository; notes: the Target's notes; testbot: Testbot's own finding"),file:as.nullable().describe("the file the step came from, relative to the component's repository; null unless source is file")}).strict().refine(t=>t.source==="file"==(t.file!==null),{path:["file"],message:"a file exactly when the step came from one"}),Hnr=/^[A-Za-z_][A-Za-z0-9_]*$/,zz=/^(?!GITHUB_)(?!SKYRAMP_RUNNER_)[A-Z][A-Z0-9_]{0,99}$/,Gz=(i=>(i.VersionEndpoint="version_endpoint",i.DeployWorkflow="deploy_workflow",i.KubernetesLabels="kubernetes_labels",i.Command="command",i.Api="api",i))(Gz||{}),kn="shared",znr=as.refine(t=>{try{let e=new URL(t);return["http:","https:"].includes(e.protocol)&&!e.username&&!e.password}catch{return!1}},"an http(s) URL with no login in it"),vI=E.object({address:znr,readyWhen:as.nullable(),credentials:E.array(E.string().regex(zz)).max(50),revisionSources:E.array(E.object({method:E.nativeEnum(Gz),detail:as.describe("what Testbot reads, such as GET /version or the deploy workflow's name"),components:E.array(as).min(1).describe("the components it tells the revision of, by name")}).strict()).max(50)}).strict(),kde={steps:E.array(qnr).max(20).optional().describe("how it starts, in order"),kind:E.enum(["web_app","service","database","external_service"]).optional(),from:E.object({file:as,service:as.nullable()}).strict().optional(),credentials:E.array(E.string().max(100).regex(Hnr)).max(50).optional().describe("the Target's credentials this component's recipe uses: a sign-in (a test user, password or token) or an API key, which the workflow supplies from a GitHub Actions secret as the environment variable of the credential's name; give each name exactly as the recipe reads it. Names only, never a value, and not a secret the recipe generates itself")},Gnr=E.object({name:as,repository:as.describe("owner/repo of the Target repository the component is built or started from, such as the one whose compose file starts its database"),healthy:E.boolean(),...kde,deployed:as.nullable().optional().describe('only with "environment": the revision the component runs, as you read it from its revision source, or null when you could not tell')}),jnr=E.object({component:as,problem:as,evidence:as.describe("the exact command and output that shows it"),fix:as.describe("what the user must provide, and where")}),Vnr=E.object({framework:as,file:as.describe("the test file run, relative to its repository root"),result:E.enum(["pass","fail","error"])}),Wnr=E.object({input:as.describe("the part of the user's SUT input, as given"),reason:as}),nk=E.object({schemaVersion:E.literal(1),status:E.nativeEnum(RI).describe("ready only if every component came up healthy and the recipe is written"),components:E.array(Gnr),suites:E.array(Vnr).default([]).describe("one run per test suite the Target's repositories have; empty when they have none"),inputsUsed:E.array(as).default([]).describe("the parts of the user's SUT input the recipe used"),inputsUsedHow:E.array(E.object({input:as.describe("exactly as written in inputsUsed; an entry that is not there is left out"),how:as.describe("what the recipe did with it")})).optional(),inputsNotUsed:E.array(Wnr).default([]).describe("the parts it did not use, and why"),blockers:E.array(jnr).describe("required (non-empty) when status is blocked"),environment:vI.optional().describe("only when the whole SUT is an existing deployment you tested where it runs, building and starting nothing: its address, what says it is ready, the credentials that reach it, and how to read what each component runs. Leave it out when any part was built or started on the runner, or reaching it needed something there (a tunnel, port-forward, proxy or client certificate)")});function _de(t){let e=Ynr(t);if(e.length>0)return e;if(t.status==="blocked"&&!(Array.isArray(t.blockers)&&t.blockers.length>0))return['status "blocked" requires at least one blocker { component, problem, evidence, fix } \u2014 say what stopped the bring-up'];if(t.status==="ready"){let r=Array.isArray(t.components)?t.components:[];if(r.length===0)return['status "ready" requires at least one component \u2014 name each component the recipe brought up healthy'];let n=r.filter(s=>s?.healthy!==!0).map(s=>String(s?.name??"?"));if(n.length>0)return[`status "ready" requires every component healthy; not healthy: ${n.join(", ")} \u2014 answer "blocked" with a blocker for each, or bring them up and answer "ready" again`]}return[]}function Ynr(t){let e=Array.isArray(t.components)?t.components:[],r=t.environment;if(!r){let a=e.filter(c=>c?.deployed!==void 0||c?.repository===kn).map(c=>String(c?.name??"?"));return a.length>0?[`"deployed" and a "${kn}" repository belong only to an answer with "environment"; remove them from: ${a.join(", ")}`]:[]}let n=[],s=e.filter(a=>a?.deployed===void 0).map(a=>String(a?.name??"?"));s.length>0&&n.push(`with "environment", every component says what it runs in "deployed" (null when you could not tell); missing for: ${s.join(", ")}`);let i=new Set(e.map(a=>a?.name)),o=(r.revisionSources??[]).flatMap(a=>a?.components??[]).filter(a=>!i.has(a));return o.length>0&&n.push(`each revision source names components of this answer; not one of them: ${o.map(String).join(", ")}`),n}var QE=64*1024,LE=512*1024,jz=/[\u0000-\u0008\u000b\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;var cu="shared-environment",Knr=1e4,dtt=5,Mde=300,Xnr=200,Znr=/\b[0-9a-fA-F]{7,64}\b/g,esr=/\b(commit|sha|revision|rev|hash)\b/i,Vz=t=>t.slice(0,Mde),sk=t=>Vz(t.trim())||"(empty response)";function ptt(t,e){let r=t.split(/\r?\n/).find(s=>s.toLowerCase().includes(e)).trim(),n=r.toLowerCase().indexOf(e);return r.length<=Mde?r:r.slice(Math.max(0,n-100),Math.max(0,n-100)+Mde)}function NI(t,e){if("error"in e)return{status:"unverifiable",observedRevision:null,evidence:sk(e.error)};let r=t.toLowerCase(),n=c=>esr.test(ptt(e.body,c)),s=(e.body.match(Znr)??[]).map(c=>c.toLowerCase()).filter(c=>/[a-f]/.test(c)||r.startsWith(c)&&n(c)),i=[...new Set(s)].filter((c,l,u)=>!u.some(d=>d!==c&&d.startsWith(c)));if(i.length>1)return{status:"unverifiable",observedRevision:null,evidence:sk(`The answer names more than one revision: ${i.join(", ")}`)};let[o]=i;return o?{status:r.startsWith(o)?"verified":"mismatch",observedRevision:o,evidence:ptt(e.body,o)}:{status:"unverifiable",observedRevision:null,evidence:sk(e.body)}}async function TI(t,e=fetch){try{let r=AbortSignal.timeout(Knr),n=new URL(t).origin,s=new URL(t);for(let i=0;;i+=1){let o=await e(s,{redirect:"manual",signal:r}),a=o.status>=300&&o.status<400?o.headers.get("location"):null;if(a){let l=new URL(a,s);if(l.origin!==n)return{error:`${t} redirects to another origin (${l.origin})`};if(i>=dtt)return{error:`${t} redirects more than ${dtt} times`};s=l;continue}let c=await o.text();return o.ok?{body:c}:{error:`${t} answered ${o.status}: ${c.trim()}`}}}catch(r){let n=r instanceof Error&&r.cause instanceof Error?`: ${r.cause.message}`:"";return{error:`${t} could not be read: ${r instanceof Error?r.message:String(r)}${n}`}}}var tsr=new Set(["version_endpoint","api"]);function Ode(t,e){let n=t.revisionSources.find(s=>tsr.has(s.method)&&s.components.includes(e))?.detail.trim().match(/^(?:(?:GET|HEAD)\s+)?(\S+)/i)?.[1];if(n)try{let s=new URL(n,t.address);return s.origin===new URL(t.address).origin?s.href:void 0}catch{return}}async function ftt(t,e,r,n=[]){let s={};for(let i of e){let o=Ode(t,i);if(!o)continue;let{observedRevision:a}=NI("",qr(await TI(o,r),n));a&&(s[i]=a)}return s}function ik(t){return(t?.components??[]).filter(e=>!!e.repository&&!!e.expectedRevision)}function Wz(t){return ik(t.sharedEnvironment).filter(e=>!e.revisionUrl)}async function rsr(t,e,r=[]){let{name:n,url:s}=t;if(!t.versionUrl)return{name:n,url:s,version:null,evidence:"No version URL is configured."};let i=qr(await TI(t.versionUrl,e),r);if("error"in i)return{name:n,url:s,version:null,evidence:sk(i.error)};let o=i.body.split(/\r?\n/).map(a=>a.trim()).find(Boolean);return{name:n,url:s,version:o?o.slice(0,Xnr):null,evidence:sk(o??"")}}var Yz=(t,e)=>!!t&&!!e&&t.toLowerCase()===e.toLowerCase(),htt=(t,e)=>t.name===e.name&&Yz(t.repository,e.repository);async function nsr(t,e,r){let{frozen:n,mergeCommit:s,mergedHead:i}=e;return!s||!i?"not_contained":i.toLowerCase()===n.toLowerCase()?"contained":r?.commitContains?r.commitContains({repository:t,ancestor:n,descendant:i}):"unknown"}async function mtt(t,e,r){let n=e.observedRevision;if(e.status!=="mismatch"||!n||!t.acceptedRevisions)return e;let{frozen:s,mergeCommit:i,mergedHead:o}=t.acceptedRevisions,a=await nsr(t.repository,t.acceptedRevisions,r),c=[s,...i&&a==="contained"?[i]:[]],l=m=>`${m===s?"the frozen revision":"the merge commit"} ${Ks(m)}`,u=(m,h)=>({status:m,observedRevision:n,evidence:Vz(`${h} (${e.evidence})`)}),d=c.find(m=>m.toLowerCase().startsWith(n));if(d)return u("verified",`observed ${Ks(n)} is ${l(d)}`);if(!r?.commitContains)return u("unverifiable",`could not tell whether observed ${Ks(n)} contains ${c.map(Ks).join(" or ")}: this run cannot compare commits`);let p=[];for(let m of c){let h=await r.commitContains({repository:t.repository,ancestor:m,descendant:n});if(h==="contained")return u("verified",`observed ${Ks(n)} contains ${l(m)}`);h==="unknown"&&p.push(m)}return p.length?u("unverifiable",`could not tell whether observed ${Ks(n)} contains ${p.map(Ks).join(" or ")}: GitHub did not answer the compare`):a==="unknown"&&o?u("unverifiable",`could not tell whether the merged head ${Ks(o)} contains ${Ks(s)}: GitHub did not answer the compare`):u("mismatch",`observed ${Ks(n)} does not contain ${c.map(Ks).join(" or ")}`)}async function Jz(t,e,r,n=[],s){let i=(a,c)=>NI(a,qr(c,n));return{components:await Promise.all(ik(t).map(async a=>{let c={name:a.name,repository:a.repository,url:a.url,expectedRevision:a.expectedRevision};if(a.revisionUrl)return{...c,source:"probe",...await mtt(a,i(a.expectedRevision,await TI(a.revisionUrl,r)),s)};let l=e.find(d=>d.component===a.name),u=i(a.expectedRevision,l?{body:l.output}:{error:"Deploy cited no check of its deployed revision."});return{...c,source:"agent",...await mtt(a,u,s)}})),dependencies:await Promise.all(t.dependencies.map(a=>rsr(a,r,n)))}}async function ssr(t,e,r,n=[]){let s=await Promise.all(e.components.map(async i=>{let o=t.components.find(u=>htt(u,i)),a=i.observedRevision?.toLowerCase();if(!a||!o?.revisionUrl)return i;let c=qr(await TI(o.revisionUrl,r),n),l=NI(i.expectedRevision,c);if(!l.observedRevision){let u="error"in c?"second read failed":"second read names no one commit",d=`first read ${Ks(i.observedRevision??a)}; ${u}: ${l.evidence}`;return{...i,status:"unverifiable",observedRevision:null,evidence:Vz(d)}}return l.observedRevision.startsWith(a)||a.startsWith(l.observedRevision)?i:{...i,status:"unverifiable",observedRevision:l.observedRevision,evidence:Vz(`changed from ${i.observedRevision} to ${l.observedRevision} during the run`)}}));return{...e,components:s}}async function gtt(t,e){let r=t.inputs.sharedEnvironment,n=Ae(t,`${cu}.json`);if(!t.inputs.appRunning||!r||!n)return;let s=await ssr(r,n,e,t.secretValues??[]);mr(t,cu,qr(s,t.secretValues??[]),[])}function ok(t){return ik(t).length>0||(t?.dependencies.length??0)>0}function Qde(t){let e=t.inputs?.sharedEnvironment;if(!ok(e))return;let r=Ae(t,`${cu}.json`);if(r)return{...r,components:ytt(e,r.components)};let n="Not checked: deploy did not complete.";return{components:ik(e).map(s=>Att(s,n)),dependencies:e.dependencies.map(s=>({name:s.name,url:s.url,version:null,evidence:n}))}}var Att=(t,e)=>({name:t.name,repository:t.repository,url:t.url,expectedRevision:t.expectedRevision,observedRevision:null,status:"unverifiable",source:t.revisionUrl?"probe":"agent",evidence:e});function ytt(t,e){let r=new Set(e.map(s=>s.name.toLowerCase())),n=ik(t).filter(s=>s.touched&&!r.has(s.name.toLowerCase()));return[...e,...n.map(s=>Att(s,"Not checked: the run recorded no read of it."))]}function BI(t){return(Qde(t)?.components??[]).filter(e=>e.status!=="verified")}function Kz(t,e,r){if(!t.appRunning||r===!1)return[];let n=(t.sharedEnvironment?.components??[]).filter(s=>s.touched);return ytt(t.sharedEnvironment,e?.components??[]).filter(s=>s.status!=="verified"&&n.some(i=>htt(i,s)))}function btt(t){let e=r=>{let n=r.observedRevision?`runs ${Ks(r.observedRevision)}`:"no revision could be read";return`${r.name} (${r.repository}) must run ${Ks(r.expectedRevision)}, but ${n}: ${r.evidence}`};return t.length?`the Test Environment does not verifiably run the change: ${t.map(e).join("; ")}`:void 0}function Xz(t){return(t?.components??[]).filter(e=>!!e.repository&&!e.expectedRevision)}function Ett(t,e=!1){return`${t.name}: ${t.repository} is not one of the run's sources, so its revision cannot be verified and ${wtt(e)}`}var wtt=t=>t?"runtime tests against it do not validate this change":"no runtime test ran against it";function xtt(t,e=!1){let r=Ks(t.expectedRevision),n=t.status==="mismatch"?`the shared environment runs ${t.repository} at ${t.observedRevision}, not ${r}`:`could not verify that the shared environment runs ${t.repository} at ${r}`;return`${t.name}: ${n}, so ${wtt(e)}`}var isr=/^\s*(POST|PUT|PATCH|DELETE)\s/i,Dde=t=>t.mutates===!0;function FE(t){return(t?.components??[]).filter(e=>!!e.repository)}function ac(t){let e=t.sharedEnvironment;return!!e&&FE(e).length>0&&!e.allowMutation&&!t.planOnly}function osr(t){let e=n=>isr.test(n.target)||Dde(n),r=[...t.generate.filter(e).map(n=>({id:n.id,target:n.target})),...t.maintenance.filter(Dde).map(n=>({id:n.test}))];return{...t,generate:t.generate.filter(n=>!e(n)),surfaces:Hz(t.surfaces,new Set(r.map(n=>n.id)),"withheld because they change a shared environment the policy protects"),maintenance:t.maintenance.filter(n=>!Dde(n)),withheld:r}}function PI(t,e){return e&&ac(t)?osr(e):e}function Zz(t){return Ae(t,"recommend.json")?.withheld??[]}function Stt(t){return`${t.id}${t.target?` (${t.target})`:""}: needs a shared-environment mutation the policy does not allow`}var asr=40,Ntt="health.command cannot be re-executed: ",Ctt=4e3,csr=9e4,lsr=5e3;function usr(t,e){let r=t.slice(0,Ctt),n=e.slice(0,Ctt);if(!r||!n)return"";let s=new Uint32Array(n.length+1),i=new Uint32Array(n.length+1),o=0,a=0;for(let c=1;c<=r.length;c++){for(let u=1;u<=n.length;u++){if(r[c-1]!==n[u-1]){i[u]=0;continue}i[u]=s[u-1]+1,i[u]>o&&(o=i[u],a=c)}let l=s;s=i,i=l}return r.slice(a-o,a)}function Itt(t){let e=t.search(/[[{]/);if(e<0)return;let r=t[e],n=r==="{"?"}":"]",s=0,i=!1,o=!1;for(let a=e;a<t.length;a++){let c=t[a];if(i){o?o=!1:c==="\\"?o=!0:c==='"'&&(i=!1);continue}if(c==='"')i=!0;else if(c===r)s++;else if(c===n&&--s===0)try{return JSON.parse(t.slice(e,a+1))}catch{return}}}function e2(t,e=0){return e>4?"\u2026":t===null?"null":Array.isArray(t)?t.length===0?"[]":`[${[...new Set(t.map(r=>e2(r,e+1)))].sort().join("|")}]`:typeof t=="object"?`{${Object.keys(t).sort().map(r=>`${r}:${e2(t[r],e+1)}`).join(",")}}`:typeof t}function Rtt(t,e){let r=Itt(t),n=Itt(e);if(r!==void 0&&n!==void 0){let a=e2(r),c=e2(n);return a===c?{ok:!0}:{ok:!1,why:`it answered ${c.slice(0,200)}, but the recorded check answered ${a.slice(0,200)}`}}let s=t.split(`
418
+ `,{mode:493})}catch{return}return`bash ${ba(e)}`}}function ba(t){return`'${t.split("'").join("'\\''")}'`}var au=$(require("fs")),oo=$(require("path"));var Cnr=oo.join(".skyramp","workspace.yml"),rtt=new Set(["playwright","cypress","selenium"]);function Vg(t){return typeof t=="string"&&t.trim()?t.trim():void 0}function dl(t){let e=oo.join(t,Cnr);if(!au.existsSync(e))return[];let r;try{r=Ig(au.readFileSync(e,"utf-8"))}catch{return[]}let n=r?.services;if(!Array.isArray(n))return[];let s=[];for(let i of n){if(typeof i!="object"||i===null)continue;let o=i,a=o.api??{},c=Vg(o.serviceName);c&&s.push({serviceName:c,language:Vg(o.language),framework:Vg(o.framework),testDirectory:Vg(o.testDirectory),schemaPath:Vg(a.schemaPath),authType:Vg(a.authType),authHeader:Vg(a.authHeader),baseUrl:Vg(a.baseUrl)})}return s}function JP(t){return t.filter(e=>!e.framework||!rtt.has(e.framework.toLowerCase()))}function ntt(t){return[...new Set(JP(t).map(e=>e.testDirectory?.replace(/\/+$/,"")).filter(e=>!!e))]}function stt(t){return[...new Set(t.filter(e=>KP(e.framework)).map(e=>e.testDirectory?.replace(/\/+$/,"")).filter(e=>!!e))]}function KP(t){return!!(t&&rtt.has(t.toLowerCase()))}var Inr={golang:"go",py:"python",py3:"python",python3:"python",ts:"typescript",js:"javascript","c++":"cpp",cplusplus:"cpp",cxx:"cpp",node:"javascript",nodejs:"javascript",rb:"ruby",cs:"csharp","c#":"csharp"};function ic(t){let e=t?.trim().toLowerCase();if(e)return Inr[e]??e}var itt={py:"python",go:"go",java:"java",kt:"kotlin",rb:"ruby",cs:"csharp",ts:"typescript",tsx:"typescript",js:"javascript",jsx:"javascript",mjs:"javascript",cjs:"javascript",kts:"kotlin",rs:"rust",php:"php",scala:"scala",swift:"swift",ex:"elixir",exs:"elixir",dart:"dart",c:"c",h:"c",cpp:"cpp",cc:"cpp",cxx:"cpp",hpp:"cpp",hh:"cpp",groovy:"groovy"},Rnr=new Set(["feature"]);function ott(t){let e=t.lastIndexOf(".");return e>=0&&Rnr.has(t.slice(e+1).toLowerCase())}var vnr=new Set(Object.values(itt));function att(t){let e=ic(t);return e!==void 0&&vnr.has(e)}function ME(t){let e=t.lastIndexOf(".");if(!(e<0))return itt[t.slice(e+1).toLowerCase()]}function Nde(t){return[...new Set(JP(t).map(e=>ic(e.language)).filter(e=>!!e))]}function CI(t,e=[]){let r=Nde(dl(t));return r.length?r:[...new Set(e.map(n=>ic(n)).filter(n=>!!n))]}function ctt(t,e,r=[]){let n=CI(t,r);if(n.length===0)return!0;let s=ic(e);return s!==void 0&&n.includes(s)}var Fz=(s=>(s.Python="python",s.Node="node",s.Jvm="jvm",s.Go="go",s))(Fz||{}),Nnr={python:"python",typescript:"node",javascript:"node",java:"jvm",kotlin:"jvm",go:"go"};function Wg(t){let e=ic(t);return e?Nnr[e]:void 0}var ltt={python:["pyproject.toml","requirements.txt","setup.py","setup.cfg","Pipfile"],node:["package.json"],jvm:["pom.xml","build.gradle","build.gradle.kts"],go:["go.mod"]},Tnr=new Set(["node_modules",".git",".venv","venv","dist","build","target","vendor",".skyramp","__pycache__"]),Bnr=3;function Pnr(t,e){let r=[],n=(s,i)=>{let o=oo.join(t,s);if(ltt[e].some(c=>au.existsSync(oo.join(o,c)))&&r.push(s),i>=Bnr)return;let a;try{a=au.readdirSync(o,{withFileTypes:!0})}catch{return}for(let c of a)c.isDirectory()&&!Tnr.has(c.name)&&!c.name.startsWith(".")&&n(s==="."?c.name:oo.join(s,c.name),i+1)};return n(".",0),r}function knr(t,e){return au.existsSync(oo.join(t,e,"tsconfig.json"))?"typescript":"javascript"}function _nr(t,e,r){let n=oo.normalize(e??".");for(;;){if(ltt[r].some(s=>au.existsSync(oo.join(t,n,s))))return n;if(n==="."||n===oo.sep||n==="")return".";n=oo.dirname(n)}}function Dnr(t,e){let r;try{r=au.readdirSync(oo.join(t,e))}catch{return!1}if(r.some(n=>/^playwright\.config\.[cm]?[jt]s$/.test(n)||/^cypress\.config\.[cm]?[jt]s$/.test(n)))return!0;for(let n of["package.json","pyproject.toml","requirements.txt"])try{if(/playwright|cypress|selenium/i.test(au.readFileSync(oo.join(t,e,n),"utf-8")))return!0}catch{}return!1}function XP(t,e){let r=dl(t),n=e==="ui"?r.filter(o=>KP(o.framework)):JP(r),s=[];for(let o of n){let a=ic(o.language),c=Wg(a);a&&s.push({language:a,dir:c?_nr(t,o.testDirectory,c):"."})}if(s.length)return ttt(s);let i=[];for(let o of Object.values(Fz))for(let a of Pnr(t,o)){if(e==="ui"&&!Dnr(t,a))continue;let c=o==="node"?knr(t,a):o==="jvm"?"java":o;i.push({language:c,dir:a})}return ttt(i)}function ttt(t){let e=new Set;return t.filter(r=>{let n=`${r.language}::${r.dir}`;return e.has(n)?!1:(e.add(n),!0)})}function Uz(t){try{return new URL(t).hostname.replace(/^\[|\]$/g,"").toLowerCase()||void 0}catch{return}}function Tde(t){if(!t)return!1;let e=t.toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="::1"||e==="0.0.0.0"||/^127(\.\d{1,3}){3}$/.test(e)}function Bde(t){let e=new Set;for(let r of dl(t)){let n=r.baseUrl&&Uz(r.baseUrl);n&&e.add(n)}return e}function $z(t,e,r=Bde(e)){let n;try{n=new URL(t).protocol}catch{return!1}if(n!=="http:"&&n!=="https:")return!1;let s=Uz(t);return s?Tde(s)||r.has(s):!1}var Cf=(s=>(s.Clean="clean",s.RecipeDrift="recipe-drift",s.ChangeBrokeBringup="change-broke-bringup",s.BringupFailed="bringup-failed",s))(Cf||{}),Yg=E.string().trim().min(1),Mnr=E.object({url:E.string().optional().describe("the URL probed, if the check is an HTTP request"),command:E.string().optional().describe("the command run, if the check is a script \u2014 preferred when auth is needed"),headers:E.record(E.string()).optional(),status:E.union([E.number(),E.string()]).optional().describe("expected HTTP status for a url check (default 200)"),output:Yg.describe("what the check returned, VERBATIM \u2014 the bytes, nothing appended; this gate RE-RUNS the check")}),ZP=E.object({schemaVersion:E.literal(1),baseUrls:E.record(E.string()).optional().describe("service \u2192 base URL of the running app; omit on a failed bring-up, never invent one"),health:Mnr.optional(),teardown:Yg.describe("command that tears the SUT down"),dependencies:E.record(E.boolean()).optional().describe("EVERY backing service: true = really deployed, false = mocked; REQUIRED when the app came up"),outcome:E.nativeEnum(Cf).describe("clean | recipe-drift (you corrected the recipe) | change-broke-bringup (the PR broke it) | bringup-failed (environment, not the PR)"),recipeFixes:E.array(E.string()).optional().describe("required when outcome is recipe-drift: what was corrected"),bringupError:E.object({command:Yg,output:Yg}).optional().describe("required when bring-up failed: the exact failing command and what it printed"),suspectFiles:E.array(E.string()).optional().describe("required for change-broke-bringup: files THIS PR changed that the failure points at, relative to your working directory (a file in another checkout of the run: its absolute path)"),seeded:E.boolean(),startedAt:Yg.describe("ISO timestamp"),revisions:E.array(E.object({component:Yg.describe("a shared component listed above"),url:Yg.describe("the URL on the component's own origin (scheme, host and port) that answers with its deployed commit"),output:Yg.describe("what the URL returned, VERBATIM; this gate FETCHES each url")})).optional().describe("only when shared components are listed above: one check per component whose deployed commit you found")});function Pde(t){let e=[],r=s=>!!s&&typeof s=="object"&&!Array.isArray(s);return t.outcome!=="change-broke-bringup"&&t.outcome!=="bringup-failed"?(!r(t.baseUrls)||Object.keys(t.baseUrls).length===0?e.push("baseUrls must be a non-empty object of service \u2192 url"):Object.values(t.baseUrls).every(s=>typeof s=="string"&&s.trim())||e.push("every baseUrls value must be a non-empty url string"),r(t.health)?!(typeof t.health.url=="string"&&t.health.url.trim())&&!(typeof t.health.command=="string"&&t.health.command.trim())&&e.push("health must record a url or a command (what you actually ran)"):e.push("health must be an object"),(!r(t.dependencies)||Object.keys(t.dependencies).length===0)&&e.push("dependencies must be a non-empty object of name \u2192 boolean (real vs mocked) when the SUT came up \u2014 account for every backing service so a mocked one can't be hidden behind a green run")):(r(t.bringupError)||e.push(`outcome "${String(t.outcome)}" requires bringupError { command, output } \u2014 the exact failing bring-up command and what it printed`),t.outcome==="change-broke-bringup"&&!(Array.isArray(t.suspectFiles)&&t.suspectFiles.length>0&&t.suspectFiles.every(s=>typeof s=="string"&&s.trim()))&&e.push("change-broke-bringup requires non-empty suspectFiles[] \u2014 the changed file(s) the failure points at; if you cannot point at a file this PR changed, the outcome is bringup-failed (environment/harness), not the PR's fault")),t.outcome==="recipe-drift"&&!(Array.isArray(t.recipeFixes)&&t.recipeFixes.length>0)&&e.push("recipe-drift outcome requires a non-empty recipeFixes[] describing what was corrected"),e}var II=(r=>(r.Full="full",r.Static="static",r))(II||{}),Ep=(n=>(n.Contract="contract",n.Integration="integration",n.Ui="ui",n))(Ep||{}),ek=(i=>(i.OwnSurface="own_surface",i.StateReadBack="state_read_back",i.Referential="referential",i.Lifecycle="lifecycle",i.Boundaries="boundaries",i))(ek||{}),OE=(s=>(s.Update="update",s.Regenerate="regenerate",s.Delete="delete",s.Verify="verify",s))(OE||{}),tk=(l=>(l.Equals="equals",l.NotEquals="not_equals",l.GreaterThan="greater_than",l.LessThan="less_than",l.Contains="contains",l.NotContains="not_contains",l.Matches="matches",l.Absent="absent",l.Present="present",l))(tk||{}),qz=["absent","present"],oc=E.string().trim().min(1),Onr=E.object({subject:oc.describe('what the test READS: a response field path, the literal "status", or the on-screen text for a ui case \u2014 the FINAL read in a multi-step case'),comparator:E.nativeEnum(tk),value:E.union([E.string(),E.number(),E.boolean(),E.null()]).optional().describe("the ONE value a broken build would not produce; OMIT for absent/present")}),Qnr=E.object({test:oc.describe("existing test path, relative to its repository"),repository:oc.optional().describe("owner/repo the test lives in, when the run has several checkouts; omit for the working checkout"),action:E.nativeEnum(OE),evidence:oc.describe("why \u2014 drift vs the diff, or a finding"),covers_behaviors:E.array(E.string()).optional().describe("analyze behavior ids this maintenance covers")}),Lnr=E.object({surface:oc.describe("a surface from the list, copied verbatim"),axis:E.nativeEnum(ek)}),Fnr=E.object({id:oc.describe("short-slug, unique across generate[]"),type:E.nativeEnum(Ep),target:oc.describe('"METHOD /path", or a business-flow name'),from_finding:E.string().optional().describe("analyze finding id this case catches"),from_behavior:E.string().optional().describe("analyze behavior id this case pins"),derived_from:Lnr.optional().describe("the surface \xD7 axis this case pins when no analyze behavior or finding names it \u2014 one of the three is required"),rationale:oc.describe("why this test matters"),expected_observable:oc.describe("one sentence for a human: what a catching test asserts, and what a broken build does instead"),expected:Onr.describe("the same intent AS DATA \u2014 see the rules below"),seededPrecondition:oc.optional().describe("seeded non-initial state + how to reach it; only when a seeded-state transition applies"),verifiable:E.boolean().describe("true only when a live SUT could confirm this test (full mode)")}),Unr=E.object({covered:E.array(E.string()).optional(),abstain:E.string().optional()}).superRefine((t,e)=>{let r=Array.isArray(t.covered),n=typeof t.abstain=="string";if(r===n)return void e.addIssue({code:E.ZodIssueCode.custom,message:"must have exactly one of covered[] or abstain"});r&&t.covered.length===0&&e.addIssue({code:E.ZodIssueCode.custom,path:["covered"],message:"must list at least one id (else abstain)"}),n&&!t.abstain.trim()&&e.addIssue({code:E.ZodIssueCode.custom,path:["abstain"],message:"must give a reason"})}).describe('{ "covered": [ids] } OR { "abstain": "reason" } \u2014 exactly one'),$nr=E.object({surface:oc.describe("a surface from the list, copied verbatim"),axes:E.object(Object.fromEntries(Object.values(ek).map(t=>[t,Unr])))}),rk=E.object({schemaVersion:E.literal(1),mode:E.nativeEnum(II),maintenance:E.array(Qnr),generate:E.array(Fnr),surfaces:E.array($nr).describe("one entry per changed surface in the list \u2014 none missing, none invented"),budget:E.object({total:E.number().describe("case count"),rationale:oc}),summary:oc.describe("one paragraph")});function Hz(t,e,r){let n=s=>{if(!s||!Array.isArray(s.covered))return s;let i=s.covered.filter(o=>!e.has(o));return i.length>0?{covered:i}:{abstain:`its only case(s) were ${r}: ${s.covered.join(", ")}`}};return t.map(s=>({...s,axes:Object.fromEntries(Object.entries(s.axes??{}).map(([i,o])=>[i,n(o)]))}))}function utt(t){let e=[],r=new Set;if(Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n?.id;typeof i=="string"&&(r.has(i)&&e.push(`generate[${s}].id "${i}" is duplicated`),r.add(i))}),Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n;!i.from_finding&&!i.from_behavior&&!i.derived_from&&e.push(`generate[${s}] carries none of from_behavior, from_finding or derived_from \u2014 say what obligation it pins`)}),Array.isArray(t.surfaces)){let n=new Set;t.surfaces.forEach((s,i)=>{let o=s;if(typeof o.surface=="string"){let a=o.surface.trim().toLowerCase();n.has(a)&&e.push(`surfaces[${i}] "${o.surface}" is listed twice`),n.add(a)}for(let[a,c]of Object.entries(o.axes??{})){let l=c?.covered;if(Array.isArray(l))for(let u of l)(typeof u!="string"||!r.has(u))&&e.push(`surfaces[${i}].axes.${a}.covered references unknown generate id ${JSON.stringify(u)}`)}})}return e}var RI=(r=>(r.Ready="ready",r.Blocked="blocked",r))(RI||{}),as=E.string().trim().min(1),qnr=E.object({action:E.enum(["start","run","wait"]),text:as,source:E.enum(["file","notes","testbot"]).describe("file: a file in the repository; notes: the Target's notes; testbot: Testbot's own finding"),file:as.nullable().describe("the file the step came from, relative to the component's repository; null unless source is file")}).strict().refine(t=>t.source==="file"==(t.file!==null),{path:["file"],message:"a file exactly when the step came from one"}),Hnr=/^[A-Za-z_][A-Za-z0-9_]*$/,zz=/^(?!GITHUB_)(?!SKYRAMP_RUNNER_)[A-Z][A-Z0-9_]{0,99}$/,Gz=(i=>(i.VersionEndpoint="version_endpoint",i.DeployWorkflow="deploy_workflow",i.KubernetesLabels="kubernetes_labels",i.Command="command",i.Api="api",i))(Gz||{}),kn="shared",znr=as.refine(t=>{try{let e=new URL(t);return["http:","https:"].includes(e.protocol)&&!e.username&&!e.password}catch{return!1}},"an http(s) URL with no login in it"),vI=E.object({address:znr,readyWhen:as.nullable(),credentials:E.array(E.string().regex(zz)).max(50),revisionSources:E.array(E.object({method:E.nativeEnum(Gz),detail:as.describe("what Testbot reads, such as GET /version or the deploy workflow's name"),components:E.array(as).min(1).describe("the components it tells the revision of, by name")}).strict()).max(50)}).strict(),kde={steps:E.array(qnr).max(20).optional().describe("how it starts, in order"),kind:E.enum(["web_app","service","database","external_service"]).optional(),from:E.object({file:as,service:as.nullable()}).strict().optional(),credentials:E.array(E.string().max(100).regex(Hnr)).max(50).optional().describe("the Target's credentials this component's recipe uses: a sign-in (a test user, password or token) or an API key, which the workflow supplies from a GitHub Actions secret as the environment variable of the credential's name; give each name exactly as the recipe reads it. Names only, never a value, and not a secret the recipe generates itself")},Gnr=E.object({name:as,repository:as.describe("owner/repo of the Target repository the component is built or started from, such as the one whose compose file starts its database"),healthy:E.boolean(),...kde,deployed:as.nullable().optional().describe('only with "environment": the revision the component runs, as you read it from its revision source, or null when you could not tell')}),jnr=E.object({component:as,problem:as,evidence:as.describe("the exact command and output that shows it"),fix:as.describe("what the user must provide, and where")}),Vnr=E.object({framework:as,file:as.describe("the test file run, relative to its repository root"),result:E.enum(["pass","fail","error"])}),Wnr=E.object({input:as.describe("the part of the user's SUT input, as given"),reason:as}),nk=E.object({schemaVersion:E.literal(1),status:E.nativeEnum(RI).describe("ready only if every component came up healthy and the recipe is written"),components:E.array(Gnr),suites:E.array(Vnr).default([]).describe("one run per test suite the Target's repositories have; empty when they have none"),inputsUsed:E.array(as).default([]).describe("the parts of the user's SUT input the recipe used"),inputsUsedHow:E.array(E.object({input:as.describe("exactly as written in inputsUsed; an entry that is not there is left out"),how:as.describe("what the recipe did with it")})).optional(),inputsNotUsed:E.array(Wnr).default([]).describe("the parts it did not use, and why"),blockers:E.array(jnr).describe("required (non-empty) when status is blocked"),environment:vI.optional().describe("only when the whole SUT is an existing deployment you tested where it runs, building and starting nothing: its address, what says it is ready, the credentials that reach it, and how to read what each component runs. Leave it out when any part was built or started on the runner, or reaching it needed something there (a tunnel, port-forward, proxy or client certificate)")});function _de(t){let e=Ynr(t);if(e.length>0)return e;if(t.status==="blocked"&&!(Array.isArray(t.blockers)&&t.blockers.length>0))return['status "blocked" requires at least one blocker { component, problem, evidence, fix } \u2014 say what stopped the bring-up'];if(t.status==="ready"){let r=Array.isArray(t.components)?t.components:[];if(r.length===0)return['status "ready" requires at least one component \u2014 name each component the recipe brought up healthy'];let n=r.filter(s=>s?.healthy!==!0).map(s=>String(s?.name??"?"));if(n.length>0)return[`status "ready" requires every component healthy; not healthy: ${n.join(", ")} \u2014 answer "blocked" with a blocker for each, or bring them up and answer "ready" again`]}return[]}function Ynr(t){let e=Array.isArray(t.components)?t.components:[],r=t.environment;if(!r){let a=e.filter(c=>c?.deployed!==void 0||c?.repository===kn).map(c=>String(c?.name??"?"));return a.length>0?[`"deployed" and a "${kn}" repository belong only to an answer with "environment"; remove them from: ${a.join(", ")}`]:[]}let n=[],s=e.filter(a=>a?.deployed===void 0).map(a=>String(a?.name??"?"));s.length>0&&n.push(`with "environment", every component says what it runs in "deployed" (null when you could not tell); missing for: ${s.join(", ")}`);let i=new Set(e.map(a=>a?.name)),o=(r.revisionSources??[]).flatMap(a=>a?.components??[]).filter(a=>!i.has(a));return o.length>0&&n.push(`each revision source names components of this answer; not one of them: ${o.map(String).join(", ")}`),n}var QE=64*1024,LE=512*1024,jz=/[\u0000-\u0008\u000b\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;var cu="shared-environment",Knr=1e4,dtt=5,Mde=300,Xnr=200,Znr=/\b[0-9a-fA-F]{7,64}\b/g,esr=/\b(commit|sha|revision|rev|hash)\b/i,Vz=t=>t.slice(0,Mde),sk=t=>Vz(t.trim())||"(empty response)";function ptt(t,e){let r=t.split(/\r?\n/).find(s=>s.toLowerCase().includes(e)).trim(),n=r.toLowerCase().indexOf(e);return r.length<=Mde?r:r.slice(Math.max(0,n-100),Math.max(0,n-100)+Mde)}function NI(t,e){if("error"in e)return{status:"unverifiable",observedRevision:null,evidence:sk(e.error)};let r=t.toLowerCase(),n=c=>esr.test(ptt(e.body,c)),s=(e.body.match(Znr)??[]).map(c=>c.toLowerCase()).filter(c=>/[a-f]/.test(c)||r.startsWith(c)&&n(c)),i=[...new Set(s)].filter((c,l,u)=>!u.some(d=>d!==c&&d.startsWith(c)));if(i.length>1)return{status:"unverifiable",observedRevision:null,evidence:sk(`The answer names more than one revision: ${i.join(", ")}`)};let[o]=i;return o?{status:r.startsWith(o)?"verified":"mismatch",observedRevision:o,evidence:ptt(e.body,o)}:{status:"unverifiable",observedRevision:null,evidence:sk(e.body)}}async function TI(t,e=fetch){try{let r=AbortSignal.timeout(Knr),n=new URL(t).origin,s=new URL(t);for(let i=0;;i+=1){let o=await e(s,{redirect:"manual",signal:r}),a=o.status>=300&&o.status<400?o.headers.get("location"):null;if(a){let l=new URL(a,s);if(l.origin!==n)return{error:`${t} redirects to another origin (${l.origin})`};if(i>=dtt)return{error:`${t} redirects more than ${dtt} times`};s=l;continue}let c=await o.text();return o.ok?{body:c}:{error:`${t} answered ${o.status}: ${c.trim()}`}}}catch(r){let n=r instanceof Error&&r.cause instanceof Error?`: ${r.cause.message}`:"";return{error:`${t} could not be read: ${r instanceof Error?r.message:String(r)}${n}`}}}var tsr=new Set(["version_endpoint","api"]);function Ode(t,e){let n=t.revisionSources.find(s=>tsr.has(s.method)&&s.components.includes(e))?.detail.trim().match(/^(?:(?:GET|HEAD)\s+)?(\S+)/i)?.[1];if(n)try{let s=new URL(n,t.address);return s.origin===new URL(t.address).origin?s.href:void 0}catch{return}}async function ftt(t,e,r,n=[]){let s={};for(let i of e){let o=Ode(t,i);if(!o)continue;let{observedRevision:a}=NI("",qr(await TI(o,r),n));a&&(s[i]=a)}return s}function ik(t){return(t?.components??[]).filter(e=>!!e.repository&&!!e.expectedRevision)}function Wz(t){return ik(t.sharedEnvironment).filter(e=>!e.revisionUrl)}async function rsr(t,e,r=[]){let{name:n,url:s}=t;if(!t.versionUrl)return{name:n,url:s,version:null,evidence:"No version URL is configured."};let i=qr(await TI(t.versionUrl,e),r);if("error"in i)return{name:n,url:s,version:null,evidence:sk(i.error)};let o=i.body.split(/\r?\n/).map(a=>a.trim()).find(Boolean);return{name:n,url:s,version:o?o.slice(0,Xnr):null,evidence:sk(o??"")}}var Yz=(t,e)=>!!t&&!!e&&t.toLowerCase()===e.toLowerCase(),htt=(t,e)=>t.name===e.name&&Yz(t.repository,e.repository);async function nsr(t,e,r){let{frozen:n,mergeCommit:s,mergedHead:i}=e;return!s||!i?"not_contained":i.toLowerCase()===n.toLowerCase()?"contained":r?.commitContains?r.commitContains({repository:t,ancestor:n,descendant:i}):"unknown"}async function mtt(t,e,r){let n=e.observedRevision;if(e.status!=="mismatch"||!n||!t.acceptedRevisions)return e;let{frozen:s,mergeCommit:i,mergedHead:o}=t.acceptedRevisions,a=await nsr(t.repository,t.acceptedRevisions,r),c=[s,...i&&a==="contained"?[i]:[]],l=m=>`${m===s?"the frozen revision":"the merge commit"} ${Ks(m)}`,u=(m,h)=>({status:m,observedRevision:n,evidence:Vz(`${h} (${e.evidence})`)}),d=c.find(m=>m.toLowerCase().startsWith(n));if(d)return u("verified",`observed ${Ks(n)} is ${l(d)}`);if(!r?.commitContains)return u("unverifiable",`could not tell whether observed ${Ks(n)} contains ${c.map(Ks).join(" or ")}: this run cannot compare commits`);let p=[];for(let m of c){let h=await r.commitContains({repository:t.repository,ancestor:m,descendant:n});if(h==="contained")return u("verified",`observed ${Ks(n)} contains ${l(m)}`);h==="unknown"&&p.push(m)}return p.length?u("unverifiable",`could not tell whether observed ${Ks(n)} contains ${p.map(Ks).join(" or ")}: GitHub did not answer the compare`):a==="unknown"&&o?u("unverifiable",`could not tell whether the merged head ${Ks(o)} contains ${Ks(s)}: GitHub did not answer the compare`):u("mismatch",`observed ${Ks(n)} does not contain ${c.map(Ks).join(" or ")}`)}async function Jz(t,e,r,n=[],s){let i=(a,c)=>NI(a,qr(c,n));return{components:await Promise.all(ik(t).map(async a=>{let c={name:a.name,repository:a.repository,url:a.url,expectedRevision:a.expectedRevision};if(a.revisionUrl)return{...c,source:"probe",...await mtt(a,i(a.expectedRevision,await TI(a.revisionUrl,r)),s)};let l=e.find(d=>d.component===a.name),u=i(a.expectedRevision,l?{body:l.output}:{error:"Deploy cited no check of its deployed revision."});return{...c,source:"agent",...await mtt(a,u,s)}})),dependencies:await Promise.all(t.dependencies.map(a=>rsr(a,r,n)))}}async function ssr(t,e,r,n=[]){let s=await Promise.all(e.components.map(async i=>{let o=t.components.find(u=>htt(u,i)),a=i.observedRevision?.toLowerCase();if(!a||!o?.revisionUrl)return i;let c=qr(await TI(o.revisionUrl,r),n),l=NI(i.expectedRevision,c);if(!l.observedRevision){let u="error"in c?"second read failed":"second read names no one commit",d=`first read ${Ks(i.observedRevision??a)}; ${u}: ${l.evidence}`;return{...i,status:"unverifiable",observedRevision:null,evidence:Vz(d)}}return l.observedRevision.startsWith(a)||a.startsWith(l.observedRevision)?i:{...i,status:"unverifiable",observedRevision:l.observedRevision,evidence:Vz(`changed from ${i.observedRevision} to ${l.observedRevision} during the run`)}}));return{...e,components:s}}async function gtt(t,e){let r=t.inputs.sharedEnvironment,n=Ae(t,`${cu}.json`);if(!t.inputs.appRunning||!r||!n)return;let s=await ssr(r,n,e,t.secretValues??[]);mr(t,cu,qr(s,t.secretValues??[]),[])}function ok(t){return ik(t).length>0||(t?.dependencies.length??0)>0}function Qde(t){let e=t.inputs?.sharedEnvironment;if(!ok(e))return;let r=Ae(t,`${cu}.json`);if(r)return{components:ytt(e,r.components),dependencies:r.dependencies};let n="Not checked: deploy did not complete.";return{components:ik(e).map(s=>Att(s,n)),dependencies:e.dependencies.map(s=>({name:s.name,url:s.url,version:null,evidence:n}))}}var Att=(t,e)=>({name:t.name,repository:t.repository,url:t.url,expectedRevision:t.expectedRevision,observedRevision:null,status:"unverifiable",source:t.revisionUrl?"probe":"agent",evidence:e});function ytt(t,e){let r=new Set(e.map(s=>s.name.toLowerCase())),n=ik(t).filter(s=>s.touched&&!r.has(s.name.toLowerCase()));return[...e,...n.map(s=>Att(s,"Not checked: the run recorded no read of it."))]}function BI(t){return(Qde(t)?.components??[]).filter(e=>e.status!=="verified")}function Kz(t,e,r){if(!t.appRunning||r===!1)return[];let n=(t.sharedEnvironment?.components??[]).filter(s=>s.touched);return ytt(t.sharedEnvironment,e?.components??[]).filter(s=>s.status!=="verified"&&n.some(i=>htt(i,s)))}function btt(t){let e=r=>{let n=r.observedRevision?`runs ${Ks(r.observedRevision)}`:"no revision could be read";return`${r.name} (${r.repository}) must run ${Ks(r.expectedRevision)}, but ${n}: ${r.evidence}`};return t.length?`the Test Environment does not verifiably run the change: ${t.map(e).join("; ")}`:void 0}function Xz(t){return(t?.components??[]).filter(e=>!!e.repository&&!e.expectedRevision)}function Ett(t,e=!1){return`${t.name}: ${t.repository} is not one of the run's sources, so its revision cannot be verified and ${wtt(e)}`}var wtt=t=>t?"runtime tests against it do not validate this change":"no runtime test ran against it";function xtt(t,e=!1){let r=Ks(t.expectedRevision),n=t.status==="mismatch"?`the shared environment runs ${t.repository} at ${t.observedRevision}, not ${r}`:`could not verify that the shared environment runs ${t.repository} at ${r}`;return`${t.name}: ${n}, so ${wtt(e)}`}var isr=/^\s*(POST|PUT|PATCH|DELETE)\s/i,Dde=t=>t.mutates===!0;function FE(t){return(t?.components??[]).filter(e=>!!e.repository)}function ac(t){let e=t.sharedEnvironment;return!!e&&FE(e).length>0&&!e.allowMutation&&!t.planOnly}function osr(t){let e=n=>isr.test(n.target)||Dde(n),r=[...t.generate.filter(e).map(n=>({id:n.id,target:n.target})),...t.maintenance.filter(Dde).map(n=>({id:n.test}))];return{...t,generate:t.generate.filter(n=>!e(n)),surfaces:Hz(t.surfaces,new Set(r.map(n=>n.id)),"withheld because they change a shared environment the policy protects"),maintenance:t.maintenance.filter(n=>!Dde(n)),withheld:r}}function PI(t,e){return e&&ac(t)?osr(e):e}function Zz(t){return Ae(t,"recommend.json")?.withheld??[]}function Stt(t){return`${t.id}${t.target?` (${t.target})`:""}: needs a shared-environment mutation the policy does not allow`}var asr=40,Ntt="health.command cannot be re-executed: ",Ctt=4e3,csr=9e4,lsr=5e3;function usr(t,e){let r=t.slice(0,Ctt),n=e.slice(0,Ctt);if(!r||!n)return"";let s=new Uint32Array(n.length+1),i=new Uint32Array(n.length+1),o=0,a=0;for(let c=1;c<=r.length;c++){for(let u=1;u<=n.length;u++){if(r[c-1]!==n[u-1]){i[u]=0;continue}i[u]=s[u-1]+1,i[u]>o&&(o=i[u],a=c)}let l=s;s=i,i=l}return r.slice(a-o,a)}function Itt(t){let e=t.search(/[[{]/);if(e<0)return;let r=t[e],n=r==="{"?"}":"]",s=0,i=!1,o=!1;for(let a=e;a<t.length;a++){let c=t[a];if(i){o?o=!1:c==="\\"?o=!0:c==='"'&&(i=!1);continue}if(c==='"')i=!0;else if(c===r)s++;else if(c===n&&--s===0)try{return JSON.parse(t.slice(e,a+1))}catch{return}}}function e2(t,e=0){return e>4?"\u2026":t===null?"null":Array.isArray(t)?t.length===0?"[]":`[${[...new Set(t.map(r=>e2(r,e+1)))].sort().join("|")}]`:typeof t=="object"?`{${Object.keys(t).sort().map(r=>`${r}:${e2(t[r],e+1)}`).join(",")}}`:typeof t}function Rtt(t,e){let r=Itt(t),n=Itt(e);if(r!==void 0&&n!==void 0){let a=e2(r),c=e2(n);return a===c?{ok:!0}:{ok:!1,why:`it answered ${c.slice(0,200)}, but the recorded check answered ${a.slice(0,200)}`}}let s=t.split(`
419
419
  `).map(a=>a.trim()).filter(Boolean).sort((a,c)=>c.length-a.length)[0]??t,i=Math.min(s.length,asr),o=usr(s,e);return o.length>=i?{ok:!0}:{ok:!1,why:`nothing in it resembles "${s.slice(0,60)}" (longest run in common: ${o.length} chars, need ${i})`}}function dsr(t){return EI(ZP,Pde,t).errors}function psr(t,e=[]){let{value:r,error:n}=Ur(t,e);if(n)return{errors:[n]};let s=dsr(r);return s.length>0?{errors:s}:{deploy:r,errors:[]}}function UE(t,e,r=[]){let n=psr(t.stdout,r);return n.deploy&&e&&(n.deploy=msr(n.deploy,e)),n}var vtt=".skyramp/sut/health-check.sh";function msr(t,e){let r=t.health?.command?.trim();return!r||!t.health||!Lz(r,Jg.join(e,vtt),"deploy")?t:{...t,health:{...t.health,command:`bash ${vtt}`}}}function fsr(){return{httpGet(t,e){let r=Tde(Uz(t))?["-k"]:[],n=(0,Lde.spawnSync)("curl",["-sS",...r,"-m","20","-o","-","-w",`
420
420
  %{http_code}`,...hsr(e),t],{encoding:"utf-8",timeout:25e3});if(n.status!==0)return{error:(n.stderr||n.error?.message||"curl failed").trim()};let s=n.stdout??"",i=s.lastIndexOf(`
421
421
  `),o=Number(s.slice(i+1).trim());return{status:Number.isFinite(o)?o:0,body:s.slice(0,i)}},runCommand(t,e){let{steps:r,reason:n}=Sf(t);if(!r)return{exitCode:1,output:`${Ntt}${n}`};let s="";for(let i of r){let o=(0,Lde.spawnSync)(i[0],i.slice(1),{cwd:e,encoding:"utf-8",timeout:6e4,env:zt()});if(s+=`${o.stdout??""}${o.stderr??""}`,(o.status??1)!==0)return{exitCode:o.status??1,output:s}}return{exitCode:0,output:s}}}}function hsr(t){return t?Object.entries(t).flatMap(([e,r])=>["-H",`${e}: ${r}`]):[]}function Ttt(t){return t.trim().replace(/^\.\//,"").replace(/\/+$/,"")}function gsr(t){if(!t.inputs)return[];let e=Xs(t),r=s=>{let i=typeof s=="string"?s:s?.path??s?.file;return typeof i=="string"&&i.trim()?Ttt(i):void 0},n=(s,i)=>s?(i??[]).flatMap(o=>{let a=r(o);return a?[{repository:s,path:a}]:[]}):[];return[...n(ws(t.inputs).slug,[...e?.changedFiles??[],...e?.newFiles??[]]),...(e?.relatedChanges??[]).flatMap(s=>n(s.repository,s.changedFiles))]}function Asr(t,e){let r=Jg.resolve(t.inputs.repositoryPath,e.trim()),n=Dz(t.inputs,r),s=n&&Jg.relative(n.path,r);return n&&s?{repository:n.slug,path:s.split(Jg.sep).join("/")}:void 0}function Btt(t=fsr(),e={}){let r=e.budgetMs??csr,n=e.intervalMs??lsr,s=e.sleep??(i=>new Promise(o=>setTimeout(o,i)));return{name:"deploy-health",async verify(i,o){let{deploy:a,errors:c}=UE(o,i.inputs?.repositoryPath,i.secretValues);if(!a)return{name:this.name,passed:!1,details:c.slice(0,6).join("; ")};if(a.outcome==="bringup-failed")return{name:this.name,passed:!0};if(a.outcome==="change-broke-bringup"){let x=gsr(i),I=(a.suspectFiles??[]).map(Ttt),v=I.filter(T=>{let N=Asr(i,T);return!!N&&wI(x,N.repository,N.path)});return x.length>0&&v.length===0?{name:this.name,passed:!1,details:`change-broke-bringup claimed, but none of suspectFiles [${I.slice(0,4).join(", ")}] is a file this PR changed \u2014 that is not attributable to the PR. Re-run bring-up; if it still fails for a reason outside the diff, record outcome "bringup-failed" (with bringupError) instead.`}:{name:this.name,passed:!0}}let l=a.health;if(!l)return{name:this.name,passed:!1,details:"health is missing although the app is recorded as up"};let u=Object.values(l.headers??{}).some(x=>/<[^>]+>/.test(String(x))),d=(x,I=!1)=>({ok:!1,details:x,transient:I}),p=()=>{if(!$z(l.url,i.inputs.repositoryPath))return d(`health url ${l.url} is not the app under test \u2014 this gate probes only loopback or a host declared in .skyramp/workspace.yml, never an arbitrary destination. Record the URL the deployed app actually answers on.`);let x=t.httpGet(l.url,l.headers);if("error"in x)return d(`health url ${l.url} unreachable: ${x.error}`,!0);let I=Number(l.status??200);if(x.status!==I)return d(`health url returned ${x.status}, expected ${I}`,!0);if(!x.body.trim())return d("health url returned empty body \u2014 must return data",!0);let v=(l.output??"").trim();if(v){let T=Rtt(v,x.body);if(!T.ok)return d(`health url ${l.url} no longer answers as recorded \u2014 ${T.why}. Either the app is not answering as it did at deploy time, or health.output is not verbatim: record ONLY the response body, with no commentary appended.`)}return{ok:!0}},m=()=>{let x=t.runCommand(l.command,i.inputs.repositoryPath),I=x.output.startsWith(Ntt);if(x.exitCode!==0)return d(`health command exited ${x.exitCode}: ${x.output.slice(0,200)}`,!I);if(!x.output.trim())return d("health command produced no output",!0);let v=(l.output??"").trim();if(v.length<16)return d(`health command output "${v}" is too thin to be a data check \u2014 the check must return real application data, not a status token`);let T=Rtt(v,x.output);return T.ok?{ok:!0}:d(`health command did not reproduce its recorded check \u2014 ${T.why}. Either the app is not answering as it did at deploy time, or health.output is not verbatim: record ONLY what the command wrote, with no commentary appended.`)},h;if(l.command&&(u||!l.url))h=m;else{if(l.url&&u)return{name:this.name,passed:!1,details:`health.headers contains a documented placeholder (${Object.entries(l.headers??{}).filter(([,x])=>/<[^>]+>/.test(String(x))).map(([x])=>x).join(", ")}), and this gate RE-EXECUTES the probe \u2014 a placeholder cannot authenticate. Record a health.command instead (a script that fetches its own token and hits the URL); do not put a real credential in the artifact.`};l.url?h=p:l.command&&(h=m)}if(!h)return{name:this.name,passed:!1,details:"health has neither url nor command"};let f=Date.now(),y=f+r,b=h();for(;!b.ok&&b.transient&&Date.now()+n<y;)await s(n),b=h();if(b.ok)return{name:this.name,passed:!0};let A=Math.round((Date.now()-f)/1e3);return{name:this.name,passed:!1,details:b.transient&&A>0?`${b.details} (still failing after ${A}s)`:b.details}}}}function cc(t){return Ude(t)&&BI(t).length===0&&Xz(t.inputs?.sharedEnvironment).length===0}function Ude(t){let e=ysr(t);if(!e&&t.state.stages.deploy?.status!=="passed")return!1;let r=Ae(t,"deploy.json");return r?r.outcome==="clean"||r.outcome==="recipe-drift":!e}function ysr(t){let e=t.state.stages.plan,r=t.state.stages.deploy;return!(t.inputs?.pipeline?t.inputs.pipeline==="two-step":!r)||e?.status!=="passed"?!1:!r||r.updatedAt<=e.updatedAt}async function bsr(t,e,r){let n=new URL(e.url).origin;return(URL.canParse(t.url)?new URL(t.url).origin:t.url)===n?TI(t.url,r):{error:`${t.url} is not on ${n}, where ${e.name} runs`}}function Ptt(t){return{name:"shared-revisions",async verify(e,r){let{deploy:n}=UE(r,e.inputs?.repositoryPath,e.secretValues),s=Wz(e.inputs??{}),i=[];for(let o of n?.revisions??[]){let a=s.find(d=>d.name===o.component);if(!a){i.push(`revisions names "${o.component}", which is not a shared component listed for a revision check`);continue}let c=await bsr(o,a,t);if("error"in c){i.push(`the revision check of ${a.name} could not be re-run: ${qr(c.error,e.secretValues??[]).slice(0,200)}`);continue}let l=NI(a.expectedRevision,{body:o.output}),u=NI(a.expectedRevision,c);l.observedRevision!==u.observedRevision&&i.push(`the revision check of ${a.name} names ${u.observedRevision??"no commit"} when re-run, but its recorded output names ${l.observedRevision??"no commit"} \u2014 record what the check returned, verbatim, or leave the component out`)}return i.length?{name:this.name,passed:!1,details:i.join("; ")}:{name:this.name,passed:!0}}}}async function ktt(t,e,r){let n=t.inputs?.sharedEnvironment;if(!ok(n))return{};let{deploy:s}=UE(e,t.inputs.repositoryPath,t.secretValues),i=await Jz(n,s?.revisions??[],r,t.secretValues??[]);return mr(t,cu,qr(i,t.secretValues??[]),[])}function _tt(t,e){let{deploy:r,errors:n}=UE(e,t.inputs?.repositoryPath,t.secretValues),s=r?.health?.headers?{...r,health:{...r.health,headers:Object.fromEntries(Object.keys(r.health.headers).map(o=>[o,"<redacted>"]))}}:r,i=qr(s,t.secretValues??[]);return mr(t,"deploy",i,n)}var $tt=require("child_process"),ck=$(require("fs")),t2=$(require("path"));var If=(o=>(o.Place="place",o.Update="update",o.Regenerate="regenerate",o.Delete="delete",o.Verify="verify",o.None="none",o))(If||{}),Rf=(n=>(n.Pass="pass",n.Fail="fail",n.Skip="skip",n))(Rf||{}),pl=E.string().trim().min(1),Dtt=E.object({case:pl.describe("a covers id \u2014 the recommend case this test realizes"),status:E.nativeEnum(Rf)}),Mtt=E.object({exit:E.number({invalid_type_error:"must be a number or null"}).nullable().describe("process exit of the re-run; null when no SUT was available"),details:E.string().optional().describe("what failed, or why a file was not run \u2014 required on any non-zero exit"),tests:E.array(Dtt).optional().describe("ONE ENTRY PER CASE the file covers; must agree with exit (0 \u2192 no fail; non-zero \u2192 at least one)")}),Ott=E.object({from:E.string().optional().describe("staged path \u2014 required for placements"),file:pl.describe("final path relative to its repository, inside that checkout, with a source-file extension"),repository:pl.optional().describe("owner/repo the file lives in, when the run has several checkouts; omit for the working checkout"),action:E.nativeEnum(If),covers:E.array(E.string()).optional().describe("recommend ids a placed test covers"),repro:E.boolean().optional().describe("this test is MEANT to fail \u2014 it reproduces a reported bug"),finding:E.boolean().optional().describe("a non-repro test that failed on a REAL product bug"),placementBroken:E.boolean().optional().describe('placement/harness problem one repair could not fix \u2014 every reran.tests entry is then "skip"'),keptReason:pl.optional().describe("why a planned delete/regenerate was declined and the file kept"),isolatedRun:pl.optional().describe('only for a test marked "runs alone": the command, from its checkout root and without a shell, that runs only this file and writes its JUnit XML into $SKYRAMP_RESULTS_DIR (named by its path: no shell expands it) \u2014 the harness runs it, so leave reran.exit null'),reran:Mtt,assertionCount:E.number().int().nonnegative().optional().describe("[derived] assertions reachable from the file, counted at write time")}).refine(t=>t.action!=="place"||typeof t.from=="string"&&t.from.trim().length>0,{message:'is a place but has no "from" staged path',path:[]}),Qtt=(r=>(r.Junit="junit",r.Converter="converter",r))(Qtt||{}),Esr=pl.optional().describe("the items[].file this test is in \u2014 needed only when two of this suite's files cover the same case id"),wsr=E.object({results:pl.describe("the JUnit XML file this run wrote, a plain file name inside $SKYRAMP_RESULTS_DIR (e.g. backend.xml)"),source:E.nativeEnum(Qtt),run:pl.describe("the command you ran that wrote it, exactly as you ran it (with any converter)"),files:E.array(pl).min(1).describe("the items[].file paths this run covered"),cases:E.array(E.object({test:pl.describe("the test's name as the runner reports it, qualified by its class or file (e.g. tests/test_a.py::test_x) when the bare name repeats"),case:pl.describe("the covers id it realizes"),file:Esr})).describe("map each reported test name to the case it covers")}),xsr=E.object({suites:E.array(wsr).min(1)}),ak=E.object({schemaVersion:E.literal(1),items:E.array(Ott),runnerResults:xsr.optional().describe("the JUnit XML your test runs wrote into $SKYRAMP_RESULTS_DIR, so the harness reads each test's result from the runner \u2014 omit only when no SUT is available"),ignored:E.array(E.string()).describe("existing tests assessed and deliberately left untouched"),summary:pl.describe("one paragraph")});var qtt="test-execution-contexts.json",Isr="localhost:35142",Htt=10*6e4,Rsr=5e3,Ltt=4e3,$de=1e4,Ftt=3e4,vsr=2e3;function ztt(t){return FE(t.sharedEnvironment).length?"shared":"disposable"}function lk(t,e){return t?.length?e||t.some(r=>r.kind!=="seed"||!!r.cleanup):!1}function Nsr(t,e,r){if(r)return"its setup would change the shared environment, which the policy does not allow";let n=t.find(i=>i.mechanism==="recipe_override");if(n)return`the Runtime Plan cannot restart a component with an override for ${n.target}`;if(!e?.trim())return"adapt recorded no command that runs it alone";let{reason:s}=Sf(e);return s?`its command cannot run without a shell (${s})`:void 0}function r2(t,e,r){let n=r?Dr(t,r):void 0;return n&&e.find(s=>Dr(t,s.file)===n)?.context||[]}var qde=t=>({status:"not_run",notRunReason:"isolation_unavailable",cleanup:{status:"skipped",detail:`not run: ${t}`}});function Gtt(t,e,r){let n=ac(t),s=ztt(t),i=[];for(let o of r){if(o.action==="delete"||!o.from)continue;let a=r2(t.repositoryPath,e,o.from);if(!lk(a,n))continue;let c=Nsr(a,o.isolatedRun,n);i.push({file:o.file,...o.repository?{repository:o.repository}:{},covers:o.covers??[],scope:s,execution:"serial",setup:a,...o.isolatedRun?{run:o.isolatedRun}:{},...c?qde(c):{status:"pending",notRunReason:null,cleanup:{status:"pending",detail:""}}})}return i}function Kg(t,e){let r=t2.join(t.outputsDir,qtt);ck.writeFileSync(`${r}.tmp`,JSON.stringify(qr(e,t.secretValues??[]),null,2)),ck.renameSync(`${r}.tmp`,r)}function $E(t){let e=gp(t2.join(t.outputsDir,qtt));return Array.isArray(e)?e:[]}var Hde=t=>t instanceof Error?t.message:String(t),Utt=t=>new Promise(e=>setTimeout(e,t));async function jtt(t,e=vsr){let r=`http://${t}/skyramp/mocks`,n;try{n=await fetch(r,{method:"DELETE",signal:AbortSignal.timeout($de)})}catch(i){throw new Error(`the Skyramp worker at ${t} could not be reached: ${Hde(i)}`)}if(!n.ok)throw new Error(`the Skyramp worker at ${t} answered ${n.status} to removing its mocks`);n.status===202&&await Utt(e);let s=Date.now()+Ftt;for(;;){try{let i=await fetch(r,{signal:AbortSignal.timeout($de)});if(i.ok&&!(await i.text()).trim()&&(await fetch(`http://${t}/readyz`,{signal:AbortSignal.timeout($de)})).ok)return}catch{}if(Date.now()>s)throw new Error(`the Skyramp worker at ${t} still reports mocks ${Ftt/1e3}s after removing them`);await Utt(250)}}var Vtt=t=>[...new Set(t.filter(e=>e.kind==="runtime_mock"||e.mechanism==="skyramp_mocker").map(e=>e.worker?.trim()||Isr))];async function Wtt(t,e){let r="",n=i=>r=(r+i).slice(-(Ltt+1024)),s=()=>tn(r,e.secrets).slice(-Ltt);for(let i of t){if(e.signal?.aborted)return{exit:null,output:s(),cancelled:!0};let o=await new Promise(a=>{let c=(0,$tt.spawn)(i[0],i.slice(1),{cwd:e.cwd,env:e.env,stdio:["ignore","pipe","pipe"],detached:!0}),l=b=>{try{c.pid&&process.kill(-c.pid,b)}catch{}},u=!1,d=!1,p;c.stdout.on("data",b=>n(b.toString())),c.stderr.on("data",b=>n(b.toString()));let m=b=>{n(`
package/dist/post.js CHANGED
@@ -213,7 +213,7 @@ ${i.join(`
213
213
  `)}
214
214
 
215
215
  <sub>[${Oe().workflowRunLinkLabel}](${e})</sub>`}Tk();Tk();Tk();Rd();function Jj(t,e){if(process.env.GITHUB_ACTIONS)return new EA(t,hbe,e);throw new Error("Unrecognized CI environment. Set GITHUB_ACTIONS=true for GitHub Actions, or use EvalPlatform directly for eval/testing.")}mt();Rd();var IC=(s=>(s.NotFound="not_found",s.NoAccess="no_access",s.Unavailable="unavailable",s.AccessLost="access_lost",s))(IC||{}),SC=t=>t.source==="other"?{source:t.source,key:t.key}:{source:t.source,site:t.site,key:t.key},oa=t=>`${t.source}:${t.site??""}:${t.key}`;var xC=/^pasted-[0-9a-f]{16}$/,th=t=>t.trim().toUpperCase(),bA=t=>{let e=t.trim();return xC.test(e.toLowerCase())?"Pasted text":/^\d+$/.test(e)?`Confluence page ${e}`:e.toUpperCase()},Bd=(t,e)=>e?`${bA(t)} AC${e}`:bA(t),vC=(r=>(r.Sufficient="sufficient",r.Insufficient="insufficient",r))(vC||{}),RC=(d=>(d.RelatedChangeConflict="related_change_conflict",d.ReferenceOutsideTarget="reference_outside_target",d.SourceAccessLost="source_access_lost",d.ConfigurationIncomplete="configuration_incomplete",d.CredentialUnavailable="credential_unavailable",d.WorkflowBindingUnverified="workflow_binding_unverified",d.WorkflowRefUnprotected="workflow_ref_unprotected",d.DeploymentReview="deployment_review",d.SutRevisionMismatch="sut_revision_mismatch",d.IsolationUnavailable="isolation_unavailable",d.EvidenceInsufficient="evidence_insufficient",d))(RC||{}),Td=(i=>(i.CiCheck="ci_check",i.TestReport="test_report",i.StaticAnalysis="static_analysis",i.CodeReview="code_review",i.Other="other",i))(Td||{}),BC=(n=>(n.Application="application",n.Environment="environment",n.TestDefect="test_defect",n))(BC||{}),Nk=(a=>(a.AuthToken="auth_token",a.Secret="secret",a.DataConnection="data_connection",a.AppNotStarted="app_not_started",a.Login="login",a.ExternalDependency="external_dependency",a.RecordingReplay="recording_replay",a))(Nk||{});var _k=(n=>(n.Seed="seed",n.RuntimeMock="runtime_mock",n.EnvOverride="env_override",n))(_k||{}),Pk=(n=>(n.TestCode="test_code",n.SkyrampMocker="skyramp_mocker",n.RecipeOverride="recipe_override",n))(Pk||{});var wA=(r=>(r.Ready="ready",r.Blocked="blocked",r))(wA||{}),_r=g.string().trim().min(1),Fct=g.object({action:g.enum(["start","run","wait"]),text:_r,source:g.enum(["file","notes","testbot"]).describe("file: a file in the repository; notes: the Target's notes; testbot: Testbot's own finding"),file:_r.nullable().describe("the file the step came from, relative to the component's repository; null unless source is file")}).strict().refine(t=>t.source==="file"==(t.file!==null),{path:["file"],message:"a file exactly when the step came from one"}),Lct=/^[A-Za-z_][A-Za-z0-9_]*$/,Kj=/^(?!GITHUB_)(?!SKYRAMP_RUNNER_)[A-Z][A-Z0-9_]{0,99}$/,Qk=(i=>(i.VersionEndpoint="version_endpoint",i.DeployWorkflow="deploy_workflow",i.KubernetesLabels="kubernetes_labels",i.Command="command",i.Api="api",i))(Qk||{}),Un="shared",Uct=_r.refine(t=>{try{let e=new URL(t);return["http:","https:"].includes(e.protocol)&&!e.username&&!e.password}catch{return!1}},"an http(s) URL with no login in it"),CA=g.object({address:Uct,readyWhen:_r.nullable(),credentials:g.array(g.string().regex(Kj)).max(50),revisionSources:g.array(g.object({method:g.nativeEnum(Qk),detail:_r.describe("what Testbot reads, such as GET /version or the deploy workflow's name"),components:g.array(_r).min(1).describe("the components it tells the revision of, by name")}).strict()).max(50)}).strict(),Zj={steps:g.array(Fct).max(20).optional().describe("how it starts, in order"),kind:g.enum(["web_app","service","database","external_service"]).optional(),from:g.object({file:_r,service:_r.nullable()}).strict().optional(),credentials:g.array(g.string().max(100).regex(Lct)).max(50).optional().describe("the Target's credentials this component's recipe uses: a sign-in (a test user, password or token) or an API key, which the workflow supplies from a GitHub Actions secret as the environment variable of the credential's name; give each name exactly as the recipe reads it. Names only, never a value, and not a secret the recipe generates itself")},qct=g.object({name:_r,repository:_r.describe("owner/repo of the Target repository the component is built or started from, such as the one whose compose file starts its database"),healthy:g.boolean(),...Zj,deployed:_r.nullable().optional().describe('only with "environment": the revision the component runs, as you read it from its revision source, or null when you could not tell')}),$ct=g.object({component:_r,problem:_r,evidence:_r.describe("the exact command and output that shows it"),fix:_r.describe("what the user must provide, and where")}),Gct=g.object({framework:_r,file:_r.describe("the test file run, relative to its repository root"),result:g.enum(["pass","fail","error"])}),Hct=g.object({input:_r.describe("the part of the user's SUT input, as given"),reason:_r}),TC=g.object({schemaVersion:g.literal(1),status:g.nativeEnum(wA).describe("ready only if every component came up healthy and the recipe is written"),components:g.array(qct),suites:g.array(Gct).default([]).describe("one run per test suite the Target's repositories have; empty when they have none"),inputsUsed:g.array(_r).default([]).describe("the parts of the user's SUT input the recipe used"),inputsUsedHow:g.array(g.object({input:_r.describe("exactly as written in inputsUsed; an entry that is not there is left out"),how:_r.describe("what the recipe did with it")})).optional(),inputsNotUsed:g.array(Hct).default([]).describe("the parts it did not use, and why"),blockers:g.array($ct).describe("required (non-empty) when status is blocked"),environment:CA.optional().describe("only when the whole SUT is an existing deployment you tested where it runs, building and starting nothing: its address, what says it is ready, the credentials that reach it, and how to read what each component runs. Leave it out when any part was built or started on the runner, or reaching it needed something there (a tunnel, port-forward, proxy or client certificate)")});function Xj(t){let e=zct(t);if(e.length>0)return e;if(t.status==="blocked"&&!(Array.isArray(t.blockers)&&t.blockers.length>0))return['status "blocked" requires at least one blocker { component, problem, evidence, fix } \u2014 say what stopped the bring-up'];if(t.status==="ready"){let r=Array.isArray(t.components)?t.components:[];if(r.length===0)return['status "ready" requires at least one component \u2014 name each component the recipe brought up healthy'];let n=r.filter(s=>s?.healthy!==!0).map(s=>String(s?.name??"?"));if(n.length>0)return[`status "ready" requires every component healthy; not healthy: ${n.join(", ")} \u2014 answer "blocked" with a blocker for each, or bring them up and answer "ready" again`]}return[]}function zct(t){let e=Array.isArray(t.components)?t.components:[],r=t.environment;if(!r){let a=e.filter(c=>c?.deployed!==void 0||c?.repository===Un).map(c=>String(c?.name??"?"));return a.length>0?[`"deployed" and a "${Un}" repository belong only to an answer with "environment"; remove them from: ${a.join(", ")}`]:[]}let n=[],s=e.filter(a=>a?.deployed===void 0).map(a=>String(a?.name??"?"));s.length>0&&n.push(`with "environment", every component says what it runs in "deployed" (null when you could not tell); missing for: ${s.join(", ")}`);let i=new Set(e.map(a=>a?.name)),o=(r.revisionSources??[]).flatMap(a=>a?.components??[]).filter(a=>!i.has(a));return o.length>0&&n.push(`each revision source names components of this answer; not one of them: ${o.map(String).join(", ")}`),n}var rh=64*1024,nh=512*1024,Dk=/[\u0000-\u0008\u000b\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;var gbe=j(require("path"));var jl=(s=>(s.Clean="clean",s.RecipeDrift="recipe-drift",s.ChangeBrokeBringup="change-broke-bringup",s.BringupFailed="bringup-failed",s))(jl||{}),kd=g.string().trim().min(1),jct=g.object({url:g.string().optional().describe("the URL probed, if the check is an HTTP request"),command:g.string().optional().describe("the command run, if the check is a script \u2014 preferred when auth is needed"),headers:g.record(g.string()).optional(),status:g.union([g.number(),g.string()]).optional().describe("expected HTTP status for a url check (default 200)"),output:kd.describe("what the check returned, VERBATIM \u2014 the bytes, nothing appended; this gate RE-RUNS the check")}),kC=g.object({schemaVersion:g.literal(1),baseUrls:g.record(g.string()).optional().describe("service \u2192 base URL of the running app; omit on a failed bring-up, never invent one"),health:jct.optional(),teardown:kd.describe("command that tears the SUT down"),dependencies:g.record(g.boolean()).optional().describe("EVERY backing service: true = really deployed, false = mocked; REQUIRED when the app came up"),outcome:g.nativeEnum(jl).describe("clean | recipe-drift (you corrected the recipe) | change-broke-bringup (the PR broke it) | bringup-failed (environment, not the PR)"),recipeFixes:g.array(g.string()).optional().describe("required when outcome is recipe-drift: what was corrected"),bringupError:g.object({command:kd,output:kd}).optional().describe("required when bring-up failed: the exact failing command and what it printed"),suspectFiles:g.array(g.string()).optional().describe("required for change-broke-bringup: files THIS PR changed that the failure points at, relative to your working directory (a file in another checkout of the run: its absolute path)"),seeded:g.boolean(),startedAt:kd.describe("ISO timestamp"),revisions:g.array(g.object({component:kd.describe("a shared component listed above"),url:kd.describe("the URL on the component's own origin (scheme, host and port) that answers with its deployed commit"),output:kd.describe("what the URL returned, VERBATIM; this gate FETCHES each url")})).optional().describe("only when shared components are listed above: one check per component whose deployed commit you found")});function eV(t){let e=[],r=s=>!!s&&typeof s=="object"&&!Array.isArray(s);return t.outcome!=="change-broke-bringup"&&t.outcome!=="bringup-failed"?(!r(t.baseUrls)||Object.keys(t.baseUrls).length===0?e.push("baseUrls must be a non-empty object of service \u2192 url"):Object.values(t.baseUrls).every(s=>typeof s=="string"&&s.trim())||e.push("every baseUrls value must be a non-empty url string"),r(t.health)?!(typeof t.health.url=="string"&&t.health.url.trim())&&!(typeof t.health.command=="string"&&t.health.command.trim())&&e.push("health must record a url or a command (what you actually ran)"):e.push("health must be an object"),(!r(t.dependencies)||Object.keys(t.dependencies).length===0)&&e.push("dependencies must be a non-empty object of name \u2192 boolean (real vs mocked) when the SUT came up \u2014 account for every backing service so a mocked one can't be hidden behind a green run")):(r(t.bringupError)||e.push(`outcome "${String(t.outcome)}" requires bringupError { command, output } \u2014 the exact failing bring-up command and what it printed`),t.outcome==="change-broke-bringup"&&!(Array.isArray(t.suspectFiles)&&t.suspectFiles.length>0&&t.suspectFiles.every(s=>typeof s=="string"&&s.trim()))&&e.push("change-broke-bringup requires non-empty suspectFiles[] \u2014 the changed file(s) the failure points at; if you cannot point at a file this PR changed, the outcome is bringup-failed (environment/harness), not the PR's fault")),t.outcome==="recipe-drift"&&!(Array.isArray(t.recipeFixes)&&t.recipeFixes.length>0)&&e.push("recipe-drift outcome requires a non-empty recipeFixes[] describing what was corrected"),e}var ts=g.string().trim().min(1),tV=(r=>(r.TestbotManaged="testbot_managed",r.CustomerDeployed="customer_deployed",r))(tV||{}),NC=[".skyramp/sut/setup.sh",".skyramp/sut/teardown.sh"],Abe=g.object({schemaVersion:g.literal(1),type:g.nativeEnum(tV).optional(),status:g.enum(["ready","blocked"]),environment:CA.optional(),components:g.array(g.object({name:ts,repository:ts.describe(`owner/repo, or "${Un}" for a customer-deployed component no repository builds`),healthy:g.boolean(),url:g.string().min(1).nullable(),...Zj,credentials:g.array(g.string().regex(Kj)).max(50).optional(),deployed:ts.nullable().optional().describe("customer_deployed only: the revision the component runs, as setup read it (WF-SETUP-22's Deployed now), or null when it could not tell")}).strict()),suites:g.array(g.object({framework:ts,file:ts,result:g.enum(["pass","fail","error"])}).strict()),inputsUsed:g.array(ts),inputsUsedHow:g.array(g.object({input:ts,how:ts}).strict()).optional(),inputsNotUsed:g.array(g.object({input:ts,reason:ts}).strict()),blockers:g.array(g.object({component:ts,problem:ts,evidence:ts,fix:ts}).strict()),replay:g.object({outcome:ts,durationSeconds:g.number().nonnegative().nullable()}).strict().nullable(),files:g.array(g.object({path:ts,content:g.string()}).strict())}).strict().superRefine((t,e)=>{t.inputsUsedHow?.forEach((s,i)=>{t.inputsUsed.includes(s.input)||e.addIssue({code:g.ZodIssueCode.custom,path:["inputsUsedHow",i,"input"],message:"not one of inputsUsed"})}),t.components.forEach((s,i)=>{s.credentials&&new Set(s.credentials).size!==s.credentials.length&&e.addIssue({code:g.ZodIssueCode.custom,path:["components",i,"credentials"],message:"names a credential twice"})});let r=t.type==="customer_deployed";r!==(t.environment!==void 0)&&e.addIssue({code:g.ZodIssueCode.custom,path:["environment"],message:"an environment exactly when the plan's type is customer_deployed"}),t.environment&&new Set(t.environment.credentials).size!==t.environment.credentials.length&&e.addIssue({code:g.ZodIssueCode.custom,path:["environment","credentials"],message:"names a credential twice"});let n=new Set(t.components.map(s=>s.name));if(t.environment?.revisionSources.forEach((s,i)=>{s.components.forEach((o,a)=>{n.has(o)||e.addIssue({code:g.ZodIssueCode.custom,path:["environment","revisionSources",i,"components",a],message:"not one of components"})})}),t.components.forEach((s,i)=>{s.deployed!==void 0!==r&&e.addIssue({code:g.ZodIssueCode.custom,path:["components",i,"deployed"],message:"what a component runs exactly when the plan is customer_deployed"}),s.repository===Un&&!r&&e.addIssue({code:g.ZodIssueCode.custom,path:["components",i,"repository"],message:`only a customer_deployed component is ${Un}`})}),r&&(t.components.forEach((s,i)=>{t.components.findIndex(o=>o.name===s.name)!==i&&e.addIssue({code:g.ZodIssueCode.custom,path:["components",i,"name"],message:"names a component twice"})}),t.replay!==null&&e.addIssue({code:g.ZodIssueCode.custom,path:["replay"],message:"a customer_deployed plan is never replayed"}),t.files.forEach((s,i)=>{NC.includes(s.path)&&e.addIssue({code:g.ZodIssueCode.custom,path:["files",i,"path"],message:"a customer_deployed plan has no script that starts or stops the system"})})),r&&t.status==="ready"){let s=new Set(t.environment?.revisionSources.flatMap(i=>i.components));t.components.forEach((i,o)=>{i.repository!==Un&&!s.has(i.name)&&e.addIssue({code:g.ZodIssueCode.custom,path:["components",o,"name"],message:"a ready customer_deployed plan reads what every component a repository builds runs"})})}});var yYt=["clean","recipe-drift"];function _C(t){let e=gbe.posix.normalize(t);return e===t&&(e===".skyramp/workspace.yml"||e.startsWith(".skyramp/sut/")&&e.length>13)}var ybe=[".skyramp/sut/setup.sh",".skyramp/sut/teardown.sh",".skyramp/sut/health.json",".skyramp/workspace.yml"],Ebe=[".skyramp/sut/health.json",".skyramp/workspace.yml"];var Mk=(e=>(e.GitHub="github",e))(Mk||{}),iV=(i=>(i.Trigger="TRIGGER",i.Baseline="BASELINE",i.AuthoritativeRelatedChange="AUTHORITATIVE_RELATED_CHANGE",i.ConfiguredSharedDependency="CONFIGURED_SHARED_DEPENDENCY",i.ManualOverride="MANUAL_OVERRIDE",i))(iV||{}),Fk=(i=>(i.PullRequest="pull_request",i.ReadyForReview="ready_for_review",i.Schedule="schedule",i.Manual="manual",i.SutSetup="sut_setup",i))(Fk||{}),Vct=["sut_setup"],Wct=["sut_setup","schedule"];var Lk=(e=>(e.PullRequest="pull_request",e))(Lk||{}),Uk=(s=>(s.ModelProvider="model_provider",s.SutAccess="sut_access",s.Skyramp="skyramp",s.Other="other",s))(Uk||{});var qk=(s=>(s.ReportUploaded="report_uploaded",s.NoReport="no_report",s.Cancelled="cancelled",s.RecipeUploaded="recipe_uploaded",s))(qk||{}),Bbe=(r=>(r.Running="running",r.Ended="ended",r))(Bbe||{}),$k=(o=>(o.TimedOut="timed_out",o.AgentFailed="agent_failed",o.SetupFailed="setup_failed",o.CredentialMissing="credential_missing",o.RunnerLost="runner_lost",o.CheckoutFailed="checkout_failed",o))($k||{}),oV=(r=>(r.Onboard="onboard",r.Deploy="deploy",r))(oV||{}),aV=(r=>(r.Started="started",r.Finished="finished",r))(aV||{}),cV=(n=>(n.Passed="passed",n.Failed="failed",n.Skipped="skipped",n))(cV||{});var lV=(n=>(n.ChooseCredential="choose_credential",n.FreeText="free_text",n.ChooseSource="choose_source",n))(lV||{});var uV=(n=>(n.Discover="discover",n.Start="start",n.Check="check",n))(uV||{}),dV=(s=>(s.Found="found",s.Starting="starting",s.Up="up",s.OutOfScope="out_of_scope",s))(dV||{}),Wl=g.string().regex(/^[1-9][0-9]{0,18}$/),xA=g.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/),Vl=g.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),aa=g.string().regex(/^[0-9a-f]{64}$/),Ok=g.object({id:Vl,revision:Wl}).strict(),xi=g.object({provider:g.nativeEnum(Mk),providerAccountId:Wl,providerRepositoryId:Wl}).strict(),nV=t=>`${t.provider}:${t.providerRepositoryId}`,Tbe=xi.extend({namespace:g.string().min(1),name:g.string().min(1)}).strict(),bbe=g.object({ref:g.string().min(1),revision:xA}).strict(),Yct=g.object({repository:Tbe,revision:xA,ref:g.string().nullable(),reason:g.nativeEnum(iV),change:g.object({kind:g.nativeEnum(Lk),number:Wl,base:bbe.optional()}).strict().nullable(),compareWith:bbe.optional()}).strict();function Jct(t){let e=t.baseline.sources,r=t.trigger.kind==="schedule"&&t.baseline.confirmedRunId!==null;if(!e)return r?"names every source of the snapshot, once":null;if(t.baseline.confirmedRunId===null)return"a run with no Confirmed Baseline names no baseline sources";let n=new Set(t.sources.map(o=>nV(o.repository))),s=new Set(e.map(o=>nV(o.repository)));return s.size===e.length&&s.size===n.size&&[...s].every(o=>n.has(o))?null:"names every source of the snapshot, once"}var kbe=/^[A-Z][A-Z0-9_]+-[1-9][0-9]*$/,Nbe=/^[1-9][0-9]{0,18}$/,wbe=new RegExp(`${kbe.source}|${Nbe.source}`),Cbe=/^https:\/\/[a-z0-9-]+(\.[a-z0-9-]+)+$/,Kct=g.discriminatedUnion("source",[g.object({source:g.literal("jira"),site:g.string().regex(Cbe),key:g.string().regex(kbe),updated:g.string().datetime(),contentHash:aa}).strict(),g.object({source:g.literal("confluence"),site:g.string().regex(Cbe),key:g.string().regex(Nbe),version:g.number().int().positive(),contentHash:aa}).strict(),g.object({source:g.literal("other"),key:g.string().regex(xC),contentHash:aa}).strict()]),Ibe=g.union([g.literal("jira"),g.literal("confluence")]),Zct=g.object({schemaVersion:g.literal(1),items:g.array(g.union([g.object({source:Ibe,site:g.string(),key:g.string().regex(wbe),state:g.literal("read"),text:g.string(),version:g.string().min(1),contentMatches:g.boolean()}).strict(),g.object({source:Ibe,site:g.string(),key:g.string().regex(wbe),state:g.literal("not_read"),reason:g.nativeEnum(IC)}).strict(),g.object({source:g.literal("other"),key:g.string().regex(xC),state:g.literal("read"),text:g.string(),version:g.string().min(1),contentMatches:g.boolean()}).strict(),g.object({source:g.literal("other"),key:g.string().regex(xC),state:g.literal("not_read"),reason:g.nativeEnum(IC)}).strict()])),instructions:g.array(g.string()).optional()}).strict(),Xct=g.object({schemaVersion:g.literal(1),runId:Vl,skyrampOrgId:Vl,target:Ok,policy:Ok.nullable(),trigger:g.object({kind:g.nativeEnum(Fk),requestedAt:g.string().datetime()}).strict(),configuration:g.object({captureId:Vl,revision:Wl.nullable(),hash:aa}).strict(),baseline:g.object({confirmedRunId:Vl.nullable(),sources:g.array(g.object({repository:xi,revision:xA}).strict()).optional()}).strict(),sources:g.array(Yct).min(1),execution:g.object({provider:g.nativeEnum(Mk),repository:Tbe,workflowPath:g.string(),ref:g.string()}).strict(),credentials:g.array(g.object({name:g.string(),purpose:g.nativeEnum(Uk),required:g.boolean()}).strict()),requirements:g.array(Kct).min(1).optional(),instructions:g.object({contentHash:aa}).strict().optional()}).strict().superRefine((t,e)=>{let r=new Set;(t.requirements??[]).forEach((o,a)=>{o.source==="other"&&o.key!==`pasted-${o.contentHash.slice(0,16)}`&&e.addIssue({code:g.ZodIssueCode.custom,message:"is not the key of its content hash",path:["requirements",a,"key"]});let c=oa({source:o.source,key:o.key});r.has(c)&&e.addIssue({code:g.ZodIssueCode.custom,message:"names an item that the run already names",path:["requirements",a,"key"]}),r.add(c)});let n=t.trigger.kind,s=Vct.includes(n);s!==(t.policy===null)&&e.addIssue({code:g.ZodIssueCode.custom,path:["policy"],message:s?`a ${n} run has no policy`:"names the policy revision"});let i=Jct(t);i&&e.addIssue({code:g.ZodIssueCode.custom,path:["baseline","sources"],message:i}),Wct.includes(n)&&t.sources.forEach((o,a)=>{o.reason!=="BASELINE"&&e.addIssue({code:g.ZodIssueCode.custom,path:["sources",a,"reason"],message:`a ${n} run selects only BASELINE sources`})}),t.sources.forEach((o,a)=>{o.compareWith&&(o.reason!=="MANUAL_OVERRIDE"||o.change)&&e.addIssue({code:g.ZodIssueCode.custom,path:["sources",a,"compareWith"],message:"only a MANUAL_OVERRIDE source without a change names a revision to compare with"})})});var pV=(r=>(r.Person="person",r.Policy="policy",r))(pV||{}),elt=g.object({kind:g.nativeEnum(pV),name:g.string().min(1).max(256)}).strict(),xYt=g.object({schemaVersion:g.literal(1),attempt:g.object({id:Vl,number:g.number().int().positive(),deadlineAt:g.string().datetime()}).strict(),manifest:Xct,manifestHash:aa,entitlements:g.array(g.string()).optional(),runToken:g.string().min(1).optional(),requestedBy:elt.nullable().optional(),writeAllowed:g.boolean().optional()}).strict(),vYt=g.object({schemaVersion:g.literal(1),runId:Vl,execution:g.object({provider:g.nativeEnum(Mk),repository:xi,providerRunId:Wl,providerRunAttempt:g.number().int().positive(),workflowRef:g.string().min(1)}).strict(),requester:g.literal(!0).optional(),writeCheck:g.literal(!0).optional()}).strict(),Sbe=g.object({repository:xi,number:Wl}).strict(),tlt=g.discriminatedUnion("status",[g.object({status:g.literal("none")}).strict(),g.object({status:g.literal("delivered"),pullRequests:g.array(Sbe).min(1)}).strict(),g.object({status:g.literal("partial"),pullRequests:g.array(Sbe).min(1),failures:g.array(g.object({repository:xi,message:g.string()}).strict()).min(1)}).strict(),g.object({status:g.literal("failed"),message:g.string()}).strict()]),rlt=g.object({sufficiency:g.nativeEnum(vC),rationale:g.string().min(1),gaps:g.array(g.string().min(1)),acceptedEvidence:g.array(g.object({kind:g.nativeEnum(Td),repository:g.string().min(1),revision:xA,reference:g.string().min(1),summary:g.string().min(1)}).strict()),actionRequired:g.array(g.nativeEnum(RC))}).strict().superRefine((t,e)=>{t.sufficiency==="sufficient"!=(t.gaps.length===0)&&e.addIssue({code:g.ZodIssueCode.custom,path:["gaps"],message:"sufficient evidence has no gaps, and insufficient evidence names at least one"}),new Set(t.actionRequired).size!==t.actionRequired.length&&e.addIssue({code:g.ZodIssueCode.custom,path:["actionRequired"],message:"a reason appears twice"})}),IA=500,fV=2048,hV=1e3,nlt=g.object({testResults:g.array(g.object({resultId:g.string().regex(/^[^\u0000-\u001f]{1,512}$/),repository:g.string().regex(/^[A-Za-z0-9._-]{1,100}\/[A-Za-z0-9._-]{1,100}$/),testType:g.string(),endpoint:g.string(),status:g.enum(["Pass","Fail","Skipped"]),details:g.string(),fileName:g.string().optional(),testId:g.string().regex(/^[^\u0000-\u001f]{1,512}$/).optional(),failureCause:g.object({kind:g.nativeEnum(BC),family:g.nativeEnum(Nk).optional()}).strict().optional()}).strict()),validation:rlt,changes:g.array(g.object({id:g.string().min(1).max(512),text:g.string().max(16384),source:g.string().max(fV),testedBy:g.array(g.string().min(1).max(1024)).max(IA),writtenBy:g.array(g.string().min(1).max(1024)).max(IA),maintainedBy:g.array(g.string().min(1).max(1024)).max(IA)}).strict()).max(hV).optional(),traceVersion:g.literal(1)}).passthrough().superRefine((t,e)=>{let r=new Set;t.testResults.forEach((n,s)=>{let i=n.failureCause;i&&n.status==="Pass"&&e.addIssue({code:g.ZodIssueCode.custom,path:["testResults",s,"failureCause"],message:"a passing result has no failure cause"}),i&&i.kind==="environment"!=(i.family!==void 0)&&e.addIssue({code:g.ZodIssueCode.custom,path:["testResults",s,"failureCause"],message:"an environment cause names its family, and no other cause does"});let o=["testResults",s,"resultId"],a=n.resultId.slice(`${n.repository}:${n.testType}:`.length);(!n.resultId.startsWith(`${n.repository}:${n.testType}:`)||a===""||a.startsWith("/")||a.startsWith("#"))&&e.addIssue({code:g.ZodIssueCode.custom,path:o,message:"is not repository:testType:path for this result"}),r.has(n.resultId)&&e.addIssue({code:g.ZodIssueCode.custom,path:o,message:"stable identity repeated"}),r.add(n.resultId)})}),xbe=t=>t.replace(/[%:#]/g,e=>encodeURIComponent(e));function mV(t,e,r,n){let s=r.replace(/\\/g,"/"),i=s.split("/").filter(c=>c!==""&&c!==".");if(s.startsWith("/")||/^[A-Za-z]:/.test(s)||i.length===0||i.includes(".."))throw new Error(`testResultId needs a path relative to the repository root, got "${r}"`);let o=i.join("/"),a=`${t}:${e}:${xbe(o)}`;return n?`${a}#${xbe(n)}`:a}var _be=50,vbe=g.string().regex(/^(?!.*\.\.)(?!\/)(?!.*\/$)[A-Za-z0-9._/-]{1,255}$/),Pbe=g.discriminatedUnion("kind",[g.object({kind:g.literal("branch_pushed"),repository:xi,branch:vbe,commit:xA}).strict(),g.object({kind:g.enum(["pull_request_opened","pull_request_edited"]),repository:xi,number:Wl,branch:vbe}).strict()]),slt=g.object({schemaVersion:g.literal(1),run:g.object({runId:Vl,attemptNumber:g.number().int().positive(),manifestHash:aa}).strict(),target:Ok,policy:Ok,provenance:g.object({sources:g.array(g.object({repository:xi,revision:xA}).strict())}).strict(),delivery:g.object({generatedTests:tlt}).strict(),producer:g.object({testbot:g.string().regex(/^[0-9A-Za-z.+-]{1,64}$/),mcp:g.string().regex(/^[0-9A-Za-z.+-]{1,64}$/)}).strict(),report:nlt,githubWrites:g.array(Pbe).max(_be).optional()}).strict(),RYt=slt.pick({schemaVersion:!0,run:!0,target:!0,provenance:!0,producer:!0}).extend({recipe:Abe}).strict().superRefine(({recipe:t},e)=>{let r=(i,o)=>e.addIssue({code:g.ZodIssueCode.custom,path:["recipe",...i],message:o});t.status==="blocked"&&t.blockers.length===0&&r(["blockers"],"a blocked recipe names at least one blocker");let n=new Set,s=0;t.files.forEach((i,o)=>{_C(i.path)||r(["files",o,"path"],"is not .skyramp/workspace.yml or a file under .skyramp/sut/"),n.has(i.path)&&r(["files",o,"path"],"file repeated"),n.add(i.path),Dk.test(i.content)&&r(["files",o,"content"],"is not text");let a=Buffer.byteLength(i.content,"utf8");s+=a,a>rh&&r(["files",o,"content"],`larger than ${rh} bytes`)}),s>nh&&r(["files"],`recipe text over ${nh} bytes in total`)}),ilt=g.object({schemaVersion:g.literal(1),stage:g.nativeEnum(oV),event:g.nativeEnum(aV),status:g.nativeEnum(cV).optional()}).strict().refine(t=>t.status===void 0||t.event==="finished",{path:["status"],message:"only a finished stage has a status"}),DC=100,Qbe=5e3,rV=2e3,sV=100,gV=/^[A-Za-z0-9_-]{1,64}$/,Dbe=20,Obe=200,Mbe=100,Fbe=100,olt=200,alt=/^[^/\s]+\/[^/\s]+$/,Lbe=500,AV=/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/,Tc=t=>g.string().max(t).refine(e=>e.trim().length>0&&!AV.test(e),"blank, or not text"),PC={sequence:g.number().int().min(1).max(Qbe),at:g.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/)},Ube=g.discriminatedUnion("kind",[g.object({...PC,kind:g.literal("log"),phase:g.nativeEnum(uV),text:Tc(rV)}).strict(),g.object({...PC,kind:g.literal("component"),name:Tc(sV),repository:Tc(olt).refine(t=>alt.test(t)||t===Un,"not owner/name"),file:Tc(Lbe).nullable(),status:g.nativeEnum(dV),version:Tc(Fbe).optional()}).strict(),g.object({...PC,kind:g.literal("reply"),to:g.string().uuid(),accepted:g.boolean(),text:Tc(rV)}).strict(),g.object({...PC,kind:g.literal("question"),id:g.string().regex(gV),type:g.nativeEnum(lV),text:Tc(rV),component:Tc(sV).nullable(),choices:g.array(Tc(Obe)).max(Dbe),placeholder:Tc(Mbe).optional()}).strict(),g.object({...PC,kind:g.literal("delivered"),ids:g.array(g.string().uuid()).max(DC)}).strict()]).superRefine((t,e)=>{t.kind==="question"&&(t.type==="free_text"!=(t.choices.length===0)&&e.addIssue({code:g.ZodIssueCode.custom,path:["choices"],message:"choices exactly when the question is not free_text"}),new Set(t.choices).size!==t.choices.length&&e.addIssue({code:g.ZodIssueCode.custom,path:["choices"],message:"a choice twice"}))}),clt=g.object({schemaVersion:g.literal(1),events:g.array(Ube).max(DC)}).strict(),Rbe={id:g.string().uuid(),text:g.string(),by:g.string().nullable(),at:g.string()},llt=g.discriminatedUnion("kind",[g.object({...Rbe,kind:g.literal("instruction"),question:g.null()}),g.object({...Rbe,kind:g.literal("answer"),question:g.string().regex(gV)})]),ult=g.object({schemaVersion:g.literal(1),leftOut:g.array(g.string()),messages:g.array(llt).optional()}),dlt=g.object({schemaVersion:g.literal(1),configuration:g.object({captureId:Vl,revision:Wl.nullable(),hash:aa}).strict(),capture:g.object({schemaVersion:g.literal(1),settings:g.object({target:g.object({environment:g.unknown()}).passthrough(),timeoutMinutes:g.number().int().positive(),answerWaitMinutes:g.number().int().positive().optional(),testEnvironment:g.object({name:g.string().min(1),address:g.string().min(1).optional(),readyWhen:g.string().min(1).optional()}).passthrough().optional()}).passthrough(),provenance:g.object({}).passthrough(),hash:aa}).strict()}).strict(),plt=CA.extend({version:g.number().int().positive(),components:g.array(g.object({name:g.string().min(1),repository:g.string().min(1)}).strict()),contentHash:aa.optional(),files:g.array(g.object({path:g.string().refine(t=>_C(t)&&!NC.includes(t),"not a file of a customer_deployed plan"),content:g.string()}).strict()).optional()}).strict(),flt=g.object({schemaVersion:g.literal(1),testEnvironment:plt.nullable().optional(),runtimePlan:g.object({version:g.number().int().positive(),contentHash:aa,files:g.array(g.object({path:g.string().refine(_C,"not a recipe file path"),content:g.string()}).strict()).min(1)}).strict().nullable()}).strict().refine(t=>!(t.runtimePlan&&t.testEnvironment),{message:"a run pins a recipe or a customer's Test Environment, never both",path:["testEnvironment"]}),hlt=g.object({schemaVersion:g.literal(1),state:g.nativeEnum(Bbe),ending:g.nativeEnum(qk).nullable(),cause:g.nativeEnum($k).nullable(),deadlineAt:g.string().datetime()}).strict();function qbe(t){return t.reportUploaded?{schemaVersion:1,reason:"report_uploaded",cause:null}:t.recipeUploaded?{schemaVersion:1,reason:"recipe_uploaded",cause:null}:t.cancelled?{schemaVersion:1,reason:"cancelled",cause:null}:{schemaVersion:1,reason:"no_report",cause:mlt(t)}}function mlt(t){return t.credentialMissing?"credential_missing":t.checkoutFailed?"checkout_failed":t.setupFailed?"setup_failed":t.timedOut?"timed_out":"agent_failed"}var rs=t=>t.slice(0,12);var glt=["generate-unit","native-run","finalize"],Alt=["preflight","plan","write",...glt,"report","deliver"];var vA=(n=>(n.Unit="unit",n.Integration="integration",n.E2e="e2e",n))(vA||{});var Gk=1440;var RA=j(require("fs")),kc=j(require("path"));function BA(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}var ylt=8;function ce(t,e,r={}){let n=e.slice(0,ylt),s=e.length-n.length;return{name:t,passed:!1,details:n.join("; ")+(s>0?`; \u2026and ${s} more`:""),...r.fatal?{fatal:!0}:{}}}function Nc(t){if(RA.existsSync(t))try{return JSON.parse(RA.readFileSync(t,"utf-8"))}catch{return}}function ne(t,e){return Nc(kc.join(t.outputsDir,e))}function pt(t,e,r,n){if(!r)throw new Error(`${e}.json unexpectedly invalid at artifact time: ${n[0]}`);let s=kc.join(t.outputsDir,`${e}.json`);return RA.writeFileSync(s,JSON.stringify(r,null,2)+`
216
- `),{[e]:kc.relative(t.runDir,s)}}function xn(t,e){return{name:t,verify(r,n){let{errors:s}=e(r,n);return s.length===0?{name:this.name,passed:!0}:ce(this.name,s,{fatal:!0})}}}function $be(t,e){return{...t,name:e}}function Nt(t,e){return kc.relative(t,kc.resolve(t,e)).replace(/\/+$/,"")}function OC(t){return t.replace(/\s+/g," ").trim()}function Nd(t){return kc.basename(t).replace(/\.[^.]+$/,"").toLowerCase()}var ca=new RegExp("(^|/)("+["test_[^/]+\\.py","[^/]+_test\\.py","[^/]+\\.(spec|test)\\.[cm]?[jt]sx?","[^/]+_test\\.go","[^/]+Tests?\\.(java|kts?)","[^/]+_(test|spec)\\.rb","[^/]+\\.feature","[^/]+Tests?\\.cs","[^/]+_test\\.rs","tests/[^/]+\\.rs","[^/]+Test\\.php","[^/]+(Test|Spec|Suite)\\.scala","[^/]+Tests?\\.swift","[^/]+_test\\.exs","[^/]+_test\\.dart","[^/]+_test\\.(c|cc|cpp|cxx)","test_[^/]+\\.(c|cc|cpp|cxx)","[^/]+(Spec|Test)\\.groovy"].join("|")+")$","i");function _d(t){if(!t.inputs.skyrampMcp?.command)return!1;for(let e of Object.values(t.state.stages))for(let r of e.attempts??[]){let n=r.mcpServers?.skyramp;if(n!==void 0&&n!=="connected")return!1}return!0}var Gbe=j(require("fs")),Hk=j(require("path"));function Pd(t,e,r={}){let n=r.maxDepth??1/0,s=!1,i=(o,a)=>{let c;try{c=Gbe.readdirSync(o,{withFileTypes:!0})}catch{return}for(let l of c){if(s)return;let u=Hk.join(o,l.name);if(l.isDirectory())!r.skip?.has(l.name)&&a<n&&i(u,a+1);else if(e(u,Hk.relative(t,u))===!1){s=!0;return}}};i(t,0)}var zk="\xABredacted\xBB";function an(t,e){if(!t||e.length===0)return t;let r=t;for(let n of e)!n||!r.includes(n)||(r=r.split(n).join(zk));return r}function ir(t,e){if(e.length===0)return t;let r=n=>typeof n=="string"?an(n,e):Array.isArray(n)?n.map(r):n&&typeof n=="object"?Object.fromEntries(Object.entries(n).map(([s,i])=>[s,r(i)])):n;return r(t)}var MYt=new TextDecoder("utf-8",{fatal:!0});var TA=(r=>(r.Full="full",r.Static="static",r))(TA||{}),_c=(n=>(n.Contract="contract",n.Integration="integration",n.Ui="ui",n))(_c||{}),MC=(i=>(i.OwnSurface="own_surface",i.StateReadBack="state_read_back",i.Referential="referential",i.Lifecycle="lifecycle",i.Boundaries="boundaries",i))(MC||{}),sh=(s=>(s.Update="update",s.Regenerate="regenerate",s.Delete="delete",s.Verify="verify",s))(sh||{}),FC=(l=>(l.Equals="equals",l.NotEquals="not_equals",l.GreaterThan="greater_than",l.LessThan="less_than",l.Contains="contains",l.NotContains="not_contains",l.Matches="matches",l.Absent="absent",l.Present="present",l))(FC||{}),jk=["absent","present"],vi=g.string().trim().min(1),Elt=g.object({subject:vi.describe('what the test READS: a response field path, the literal "status", or the on-screen text for a ui case \u2014 the FINAL read in a multi-step case'),comparator:g.nativeEnum(FC),value:g.union([g.string(),g.number(),g.boolean(),g.null()]).optional().describe("the ONE value a broken build would not produce; OMIT for absent/present")}),blt=g.object({test:vi.describe("existing test path, relative to its repository"),repository:vi.optional().describe("owner/repo the test lives in, when the run has several checkouts; omit for the working checkout"),action:g.nativeEnum(sh),evidence:vi.describe("why \u2014 drift vs the diff, or a finding"),covers_behaviors:g.array(g.string()).optional().describe("analyze behavior ids this maintenance covers")}),wlt=g.object({surface:vi.describe("a surface from the list, copied verbatim"),axis:g.nativeEnum(MC)}),Clt=g.object({id:vi.describe("short-slug, unique across generate[]"),type:g.nativeEnum(_c),target:vi.describe('"METHOD /path", or a business-flow name'),from_finding:g.string().optional().describe("analyze finding id this case catches"),from_behavior:g.string().optional().describe("analyze behavior id this case pins"),derived_from:wlt.optional().describe("the surface \xD7 axis this case pins when no analyze behavior or finding names it \u2014 one of the three is required"),rationale:vi.describe("why this test matters"),expected_observable:vi.describe("one sentence for a human: what a catching test asserts, and what a broken build does instead"),expected:Elt.describe("the same intent AS DATA \u2014 see the rules below"),seededPrecondition:vi.optional().describe("seeded non-initial state + how to reach it; only when a seeded-state transition applies"),verifiable:g.boolean().describe("true only when a live SUT could confirm this test (full mode)")}),Ilt=g.object({covered:g.array(g.string()).optional(),abstain:g.string().optional()}).superRefine((t,e)=>{let r=Array.isArray(t.covered),n=typeof t.abstain=="string";if(r===n)return void e.addIssue({code:g.ZodIssueCode.custom,message:"must have exactly one of covered[] or abstain"});r&&t.covered.length===0&&e.addIssue({code:g.ZodIssueCode.custom,path:["covered"],message:"must list at least one id (else abstain)"}),n&&!t.abstain.trim()&&e.addIssue({code:g.ZodIssueCode.custom,path:["abstain"],message:"must give a reason"})}).describe('{ "covered": [ids] } OR { "abstain": "reason" } \u2014 exactly one'),Slt=g.object({surface:vi.describe("a surface from the list, copied verbatim"),axes:g.object(Object.fromEntries(Object.values(MC).map(t=>[t,Ilt])))}),LC=g.object({schemaVersion:g.literal(1),mode:g.nativeEnum(TA),maintenance:g.array(blt),generate:g.array(Clt),surfaces:g.array(Slt).describe("one entry per changed surface in the list \u2014 none missing, none invented"),budget:g.object({total:g.number().describe("case count"),rationale:vi}),summary:vi.describe("one paragraph")});function Vk(t,e,r){let n=s=>{if(!s||!Array.isArray(s.covered))return s;let i=s.covered.filter(o=>!e.has(o));return i.length>0?{covered:i}:{abstain:`its only case(s) were ${r}: ${s.covered.join(", ")}`}};return t.map(s=>({...s,axes:Object.fromEntries(Object.entries(s.axes??{}).map(([i,o])=>[i,n(o)]))}))}function Hbe(t){let e=[],r=new Set;if(Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n?.id;typeof i=="string"&&(r.has(i)&&e.push(`generate[${s}].id "${i}" is duplicated`),r.add(i))}),Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n;!i.from_finding&&!i.from_behavior&&!i.derived_from&&e.push(`generate[${s}] carries none of from_behavior, from_finding or derived_from \u2014 say what obligation it pins`)}),Array.isArray(t.surfaces)){let n=new Set;t.surfaces.forEach((s,i)=>{let o=s;if(typeof o.surface=="string"){let a=o.surface.trim().toLowerCase();n.has(a)&&e.push(`surfaces[${i}] "${o.surface}" is listed twice`),n.add(a)}for(let[a,c]of Object.entries(o.axes??{})){let l=c?.covered;if(Array.isArray(l))for(let u of l)(typeof u!="string"||!r.has(u))&&e.push(`surfaces[${i}].axes.${a}.covered references unknown generate id ${JSON.stringify(u)}`)}})}return e}var la="shared-environment",xlt=1e4,zbe=5,EV=300,vlt=200,Rlt=/\b[0-9a-fA-F]{7,64}\b/g,Blt=/\b(commit|sha|revision|rev|hash)\b/i,Wk=t=>t.slice(0,EV),UC=t=>Wk(t.trim())||"(empty response)";function jbe(t,e){let r=t.split(/\r?\n/).find(s=>s.toLowerCase().includes(e)).trim(),n=r.toLowerCase().indexOf(e);return r.length<=EV?r:r.slice(Math.max(0,n-100),Math.max(0,n-100)+EV)}function qC(t,e){if("error"in e)return{status:"unverifiable",observedRevision:null,evidence:UC(e.error)};let r=t.toLowerCase(),n=c=>Blt.test(jbe(e.body,c)),s=(e.body.match(Rlt)??[]).map(c=>c.toLowerCase()).filter(c=>/[a-f]/.test(c)||r.startsWith(c)&&n(c)),i=[...new Set(s)].filter((c,l,u)=>!u.some(d=>d!==c&&d.startsWith(c)));if(i.length>1)return{status:"unverifiable",observedRevision:null,evidence:UC(`The answer names more than one revision: ${i.join(", ")}`)};let[o]=i;return o?{status:r.startsWith(o)?"verified":"mismatch",observedRevision:o,evidence:jbe(e.body,o)}:{status:"unverifiable",observedRevision:null,evidence:UC(e.body)}}async function $C(t,e=fetch){try{let r=AbortSignal.timeout(xlt),n=new URL(t).origin,s=new URL(t);for(let i=0;;i+=1){let o=await e(s,{redirect:"manual",signal:r}),a=o.status>=300&&o.status<400?o.headers.get("location"):null;if(a){let l=new URL(a,s);if(l.origin!==n)return{error:`${t} redirects to another origin (${l.origin})`};if(i>=zbe)return{error:`${t} redirects more than ${zbe} times`};s=l;continue}let c=await o.text();return o.ok?{body:c}:{error:`${t} answered ${o.status}: ${c.trim()}`}}}catch(r){let n=r instanceof Error&&r.cause instanceof Error?`: ${r.cause.message}`:"";return{error:`${t} could not be read: ${r instanceof Error?r.message:String(r)}${n}`}}}var ZYt=new Set(["version_endpoint","api"]);function GC(t){return(t?.components??[]).filter(e=>!!e.repository&&!!e.expectedRevision)}function Yk(t){return GC(t.sharedEnvironment).filter(e=>!e.revisionUrl)}async function Tlt(t,e,r=[]){let{name:n,url:s}=t;if(!t.versionUrl)return{name:n,url:s,version:null,evidence:"No version URL is configured."};let i=ir(await $C(t.versionUrl,e),r);if("error"in i)return{name:n,url:s,version:null,evidence:UC(i.error)};let o=i.body.split(/\r?\n/).map(a=>a.trim()).find(Boolean);return{name:n,url:s,version:o?o.slice(0,vlt):null,evidence:UC(o??"")}}var Wbe=(t,e)=>!!t&&!!e&&t.toLowerCase()===e.toLowerCase(),Ybe=(t,e)=>t.name===e.name&&Wbe(t.repository,e.repository);async function klt(t,e,r){let{frozen:n,mergeCommit:s,mergedHead:i}=e;return!s||!i?"not_contained":i.toLowerCase()===n.toLowerCase()?"contained":r?.commitContains?r.commitContains({repository:t,ancestor:n,descendant:i}):"unknown"}async function Vbe(t,e,r){let n=e.observedRevision;if(e.status!=="mismatch"||!n||!t.acceptedRevisions)return e;let{frozen:s,mergeCommit:i,mergedHead:o}=t.acceptedRevisions,a=await klt(t.repository,t.acceptedRevisions,r),c=[s,...i&&a==="contained"?[i]:[]],l=f=>`${f===s?"the frozen revision":"the merge commit"} ${rs(f)}`,u=(f,A)=>({status:f,observedRevision:n,evidence:Wk(`${A} (${e.evidence})`)}),d=c.find(f=>f.toLowerCase().startsWith(n));if(d)return u("verified",`observed ${rs(n)} is ${l(d)}`);if(!r?.commitContains)return u("unverifiable",`could not tell whether observed ${rs(n)} contains ${c.map(rs).join(" or ")}: this run cannot compare commits`);let p=[];for(let f of c){let A=await r.commitContains({repository:t.repository,ancestor:f,descendant:n});if(A==="contained")return u("verified",`observed ${rs(n)} contains ${l(f)}`);A==="unknown"&&p.push(f)}return p.length?u("unverifiable",`could not tell whether observed ${rs(n)} contains ${p.map(rs).join(" or ")}: GitHub did not answer the compare`):a==="unknown"&&o?u("unverifiable",`could not tell whether the merged head ${rs(o)} contains ${rs(s)}: GitHub did not answer the compare`):u("mismatch",`observed ${rs(n)} does not contain ${c.map(rs).join(" or ")}`)}async function Jk(t,e,r,n=[],s){let i=(a,c)=>qC(a,ir(c,n));return{components:await Promise.all(GC(t).map(async a=>{let c={name:a.name,repository:a.repository,url:a.url,expectedRevision:a.expectedRevision};if(a.revisionUrl)return{...c,source:"probe",...await Vbe(a,i(a.expectedRevision,await $C(a.revisionUrl,r)),s)};let l=e.find(d=>d.component===a.name),u=i(a.expectedRevision,l?{body:l.output}:{error:"Deploy cited no check of its deployed revision."});return{...c,source:"agent",...await Vbe(a,u,s)}})),dependencies:await Promise.all(t.dependencies.map(a=>Tlt(a,r,n)))}}async function Nlt(t,e,r,n=[]){let s=await Promise.all(e.components.map(async i=>{let o=t.components.find(u=>Ybe(u,i)),a=i.observedRevision?.toLowerCase();if(!a||!o?.revisionUrl)return i;let c=ir(await $C(o.revisionUrl,r),n),l=qC(i.expectedRevision,c);if(!l.observedRevision){let u="error"in c?"second read failed":"second read names no one commit",d=`first read ${rs(i.observedRevision??a)}; ${u}: ${l.evidence}`;return{...i,status:"unverifiable",observedRevision:null,evidence:Wk(d)}}return l.observedRevision.startsWith(a)||a.startsWith(l.observedRevision)?i:{...i,status:"unverifiable",observedRevision:l.observedRevision,evidence:Wk(`changed from ${i.observedRevision} to ${l.observedRevision} during the run`)}}));return{...e,components:s}}async function Jbe(t,e){let r=t.inputs.sharedEnvironment,n=ne(t,`${la}.json`);if(!t.inputs.appRunning||!r||!n)return;let s=await Nlt(r,n,e,t.secretValues??[]);pt(t,la,ir(s,t.secretValues??[]),[])}function HC(t){return GC(t).length>0||(t?.dependencies.length??0)>0}function bV(t){let e=t.inputs?.sharedEnvironment;if(!HC(e))return;let r=ne(t,`${la}.json`);if(r)return{...r,components:Zbe(e,r.components)};let n="Not checked: deploy did not complete.";return{components:GC(e).map(s=>Kbe(s,n)),dependencies:e.dependencies.map(s=>({name:s.name,url:s.url,version:null,evidence:n}))}}var Kbe=(t,e)=>({name:t.name,repository:t.repository,url:t.url,expectedRevision:t.expectedRevision,observedRevision:null,status:"unverifiable",source:t.revisionUrl?"probe":"agent",evidence:e});function Zbe(t,e){let r=new Set(e.map(s=>s.name.toLowerCase())),n=GC(t).filter(s=>s.touched&&!r.has(s.name.toLowerCase()));return[...e,...n.map(s=>Kbe(s,"Not checked: the run recorded no read of it."))]}function kA(t){return(bV(t)?.components??[]).filter(e=>e.status!=="verified")}function wV(t,e,r){if(!t.appRunning||r===!1)return[];let n=(t.sharedEnvironment?.components??[]).filter(s=>s.touched);return Zbe(t.sharedEnvironment,e?.components??[]).filter(s=>s.status!=="verified"&&n.some(i=>Ybe(i,s)))}function Xbe(t){let e=r=>{let n=r.observedRevision?`runs ${rs(r.observedRevision)}`:"no revision could be read";return`${r.name} (${r.repository}) must run ${rs(r.expectedRevision)}, but ${n}: ${r.evidence}`};return t.length?`the Test Environment does not verifiably run the change: ${t.map(e).join("; ")}`:void 0}function Kk(t){return(t?.components??[]).filter(e=>!!e.repository&&!e.expectedRevision)}function ewe(t,e=!1){return`${t.name}: ${t.repository} is not one of the run's sources, so its revision cannot be verified and ${twe(e)}`}var twe=t=>t?"runtime tests against it do not validate this change":"no runtime test ran against it";function rwe(t,e=!1){let r=rs(t.expectedRevision),n=t.status==="mismatch"?`the shared environment runs ${t.repository} at ${t.observedRevision}, not ${r}`:`could not verify that the shared environment runs ${t.repository} at ${r}`;return`${t.name}: ${n}, so ${twe(e)}`}var _lt=/^\s*(POST|PUT|PATCH|DELETE)\s/i,yV=t=>t.mutates===!0;function ih(t){return(t?.components??[]).filter(e=>!!e.repository)}function Ri(t){let e=t.sharedEnvironment;return!!e&&ih(e).length>0&&!e.allowMutation&&!t.planOnly}function Plt(t){let e=n=>_lt.test(n.target)||yV(n),r=[...t.generate.filter(e).map(n=>({id:n.id,target:n.target})),...t.maintenance.filter(yV).map(n=>({id:n.test}))];return{...t,generate:t.generate.filter(n=>!e(n)),surfaces:Vk(t.surfaces,new Set(r.map(n=>n.id)),"withheld because they change a shared environment the policy protects"),maintenance:t.maintenance.filter(n=>!yV(n)),withheld:r}}function NA(t,e){return e&&Ri(t)?Plt(e):e}function Zk(t){return ne(t,"recommend.json")?.withheld??[]}function nwe(t){return`${t.id}${t.target?` (${t.target})`:""}: needs a shared-environment mutation the policy does not allow`}var qA=j(require("fs")),UA=j(require("path"));function Ht(t,e=[]){let r=t.trim();if(!r)return{error:"session produced no output"};let n=c=>{try{let l=JSON.parse(c);return typeof l=="object"&&l!==null&&!Array.isArray(l)?l:void 0}catch{return}},s=n(r);if(s!==void 0)return{value:s};let i;if(r.startsWith("{")&&r.endsWith("}"))try{JSON.parse(r)}catch(c){i=c instanceof Error?c.message:String(c)}let o=[...r.matchAll(/```(?:json)?\s*\n([\s\S]*?)```/g)];for(let c=o.length-1;c>=0;c--){let l=n(o[c][1].trim());if(l!==void 0)return{value:l}}let a;for(let c=r.indexOf("{");c!==-1;c=r.indexOf("{",c+1)){let l=0,u=!1,d=!1;for(let p=c;p<r.length;p++){let f=r[p];if(d){d=!1;continue}if(f==="\\"){d=u;continue}if(f==='"'){u=!u;continue}if(!u){if(f==="{")l++;else if(f==="}"&&(l--,l===0)){let A=n(r.slice(c,p+1));A!==void 0&&Object.keys(A).length>0&&(a=A,c=p);break}}}}return i&&(a===void 0||Object.keys(a).length<3)?{error:`final message is not valid JSON \u2014 ${i}. Most often an unescaped double quote inside a string (e.g. in "summary" or "evidence"): escape it as \\" or use single quotes in prose`}:a!==void 0?{value:a}:i?{error:`final message is not valid JSON \u2014 ${i}. Most often an unescaped double quote inside a string (e.g. in "summary" or "evidence"): escape it as \\" or use single quotes in prose`}:{error:`no parseable JSON object found in session output \u2014 the final message was: "${Qlt(an(r,e))}"`}}var swe=240;function Qlt(t){let e=t.replace(/\s+/g," ").trim();return e.length<=swe?e:`\u2026${e.slice(-swe)}`}function Jt(t,e=0,r=new Set){return zC(t,e,r)}var iwe=t=>" ".repeat(t);function zC(t,e,r){let n=Dlt(t);switch(n._def.typeName){case"ZodObject":{let i=n.shape,o=Object.keys(i).filter(c=>!r.has(c)&&!i[c].description?.startsWith("[derived]"));return o.length===0?"{}":`{
216
+ `),{[e]:kc.relative(t.runDir,s)}}function xn(t,e){return{name:t,verify(r,n){let{errors:s}=e(r,n);return s.length===0?{name:this.name,passed:!0}:ce(this.name,s,{fatal:!0})}}}function $be(t,e){return{...t,name:e}}function Nt(t,e){return kc.relative(t,kc.resolve(t,e)).replace(/\/+$/,"")}function OC(t){return t.replace(/\s+/g," ").trim()}function Nd(t){return kc.basename(t).replace(/\.[^.]+$/,"").toLowerCase()}var ca=new RegExp("(^|/)("+["test_[^/]+\\.py","[^/]+_test\\.py","[^/]+\\.(spec|test)\\.[cm]?[jt]sx?","[^/]+_test\\.go","[^/]+Tests?\\.(java|kts?)","[^/]+_(test|spec)\\.rb","[^/]+\\.feature","[^/]+Tests?\\.cs","[^/]+_test\\.rs","tests/[^/]+\\.rs","[^/]+Test\\.php","[^/]+(Test|Spec|Suite)\\.scala","[^/]+Tests?\\.swift","[^/]+_test\\.exs","[^/]+_test\\.dart","[^/]+_test\\.(c|cc|cpp|cxx)","test_[^/]+\\.(c|cc|cpp|cxx)","[^/]+(Spec|Test)\\.groovy"].join("|")+")$","i");function _d(t){if(!t.inputs.skyrampMcp?.command)return!1;for(let e of Object.values(t.state.stages))for(let r of e.attempts??[]){let n=r.mcpServers?.skyramp;if(n!==void 0&&n!=="connected")return!1}return!0}var Gbe=j(require("fs")),Hk=j(require("path"));function Pd(t,e,r={}){let n=r.maxDepth??1/0,s=!1,i=(o,a)=>{let c;try{c=Gbe.readdirSync(o,{withFileTypes:!0})}catch{return}for(let l of c){if(s)return;let u=Hk.join(o,l.name);if(l.isDirectory())!r.skip?.has(l.name)&&a<n&&i(u,a+1);else if(e(u,Hk.relative(t,u))===!1){s=!0;return}}};i(t,0)}var zk="\xABredacted\xBB";function an(t,e){if(!t||e.length===0)return t;let r=t;for(let n of e)!n||!r.includes(n)||(r=r.split(n).join(zk));return r}function ir(t,e){if(e.length===0)return t;let r=n=>typeof n=="string"?an(n,e):Array.isArray(n)?n.map(r):n&&typeof n=="object"?Object.fromEntries(Object.entries(n).map(([s,i])=>[s,r(i)])):n;return r(t)}var MYt=new TextDecoder("utf-8",{fatal:!0});var TA=(r=>(r.Full="full",r.Static="static",r))(TA||{}),_c=(n=>(n.Contract="contract",n.Integration="integration",n.Ui="ui",n))(_c||{}),MC=(i=>(i.OwnSurface="own_surface",i.StateReadBack="state_read_back",i.Referential="referential",i.Lifecycle="lifecycle",i.Boundaries="boundaries",i))(MC||{}),sh=(s=>(s.Update="update",s.Regenerate="regenerate",s.Delete="delete",s.Verify="verify",s))(sh||{}),FC=(l=>(l.Equals="equals",l.NotEquals="not_equals",l.GreaterThan="greater_than",l.LessThan="less_than",l.Contains="contains",l.NotContains="not_contains",l.Matches="matches",l.Absent="absent",l.Present="present",l))(FC||{}),jk=["absent","present"],vi=g.string().trim().min(1),Elt=g.object({subject:vi.describe('what the test READS: a response field path, the literal "status", or the on-screen text for a ui case \u2014 the FINAL read in a multi-step case'),comparator:g.nativeEnum(FC),value:g.union([g.string(),g.number(),g.boolean(),g.null()]).optional().describe("the ONE value a broken build would not produce; OMIT for absent/present")}),blt=g.object({test:vi.describe("existing test path, relative to its repository"),repository:vi.optional().describe("owner/repo the test lives in, when the run has several checkouts; omit for the working checkout"),action:g.nativeEnum(sh),evidence:vi.describe("why \u2014 drift vs the diff, or a finding"),covers_behaviors:g.array(g.string()).optional().describe("analyze behavior ids this maintenance covers")}),wlt=g.object({surface:vi.describe("a surface from the list, copied verbatim"),axis:g.nativeEnum(MC)}),Clt=g.object({id:vi.describe("short-slug, unique across generate[]"),type:g.nativeEnum(_c),target:vi.describe('"METHOD /path", or a business-flow name'),from_finding:g.string().optional().describe("analyze finding id this case catches"),from_behavior:g.string().optional().describe("analyze behavior id this case pins"),derived_from:wlt.optional().describe("the surface \xD7 axis this case pins when no analyze behavior or finding names it \u2014 one of the three is required"),rationale:vi.describe("why this test matters"),expected_observable:vi.describe("one sentence for a human: what a catching test asserts, and what a broken build does instead"),expected:Elt.describe("the same intent AS DATA \u2014 see the rules below"),seededPrecondition:vi.optional().describe("seeded non-initial state + how to reach it; only when a seeded-state transition applies"),verifiable:g.boolean().describe("true only when a live SUT could confirm this test (full mode)")}),Ilt=g.object({covered:g.array(g.string()).optional(),abstain:g.string().optional()}).superRefine((t,e)=>{let r=Array.isArray(t.covered),n=typeof t.abstain=="string";if(r===n)return void e.addIssue({code:g.ZodIssueCode.custom,message:"must have exactly one of covered[] or abstain"});r&&t.covered.length===0&&e.addIssue({code:g.ZodIssueCode.custom,path:["covered"],message:"must list at least one id (else abstain)"}),n&&!t.abstain.trim()&&e.addIssue({code:g.ZodIssueCode.custom,path:["abstain"],message:"must give a reason"})}).describe('{ "covered": [ids] } OR { "abstain": "reason" } \u2014 exactly one'),Slt=g.object({surface:vi.describe("a surface from the list, copied verbatim"),axes:g.object(Object.fromEntries(Object.values(MC).map(t=>[t,Ilt])))}),LC=g.object({schemaVersion:g.literal(1),mode:g.nativeEnum(TA),maintenance:g.array(blt),generate:g.array(Clt),surfaces:g.array(Slt).describe("one entry per changed surface in the list \u2014 none missing, none invented"),budget:g.object({total:g.number().describe("case count"),rationale:vi}),summary:vi.describe("one paragraph")});function Vk(t,e,r){let n=s=>{if(!s||!Array.isArray(s.covered))return s;let i=s.covered.filter(o=>!e.has(o));return i.length>0?{covered:i}:{abstain:`its only case(s) were ${r}: ${s.covered.join(", ")}`}};return t.map(s=>({...s,axes:Object.fromEntries(Object.entries(s.axes??{}).map(([i,o])=>[i,n(o)]))}))}function Hbe(t){let e=[],r=new Set;if(Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n?.id;typeof i=="string"&&(r.has(i)&&e.push(`generate[${s}].id "${i}" is duplicated`),r.add(i))}),Array.isArray(t.generate)&&t.generate.forEach((n,s)=>{let i=n;!i.from_finding&&!i.from_behavior&&!i.derived_from&&e.push(`generate[${s}] carries none of from_behavior, from_finding or derived_from \u2014 say what obligation it pins`)}),Array.isArray(t.surfaces)){let n=new Set;t.surfaces.forEach((s,i)=>{let o=s;if(typeof o.surface=="string"){let a=o.surface.trim().toLowerCase();n.has(a)&&e.push(`surfaces[${i}] "${o.surface}" is listed twice`),n.add(a)}for(let[a,c]of Object.entries(o.axes??{})){let l=c?.covered;if(Array.isArray(l))for(let u of l)(typeof u!="string"||!r.has(u))&&e.push(`surfaces[${i}].axes.${a}.covered references unknown generate id ${JSON.stringify(u)}`)}})}return e}var la="shared-environment",xlt=1e4,zbe=5,EV=300,vlt=200,Rlt=/\b[0-9a-fA-F]{7,64}\b/g,Blt=/\b(commit|sha|revision|rev|hash)\b/i,Wk=t=>t.slice(0,EV),UC=t=>Wk(t.trim())||"(empty response)";function jbe(t,e){let r=t.split(/\r?\n/).find(s=>s.toLowerCase().includes(e)).trim(),n=r.toLowerCase().indexOf(e);return r.length<=EV?r:r.slice(Math.max(0,n-100),Math.max(0,n-100)+EV)}function qC(t,e){if("error"in e)return{status:"unverifiable",observedRevision:null,evidence:UC(e.error)};let r=t.toLowerCase(),n=c=>Blt.test(jbe(e.body,c)),s=(e.body.match(Rlt)??[]).map(c=>c.toLowerCase()).filter(c=>/[a-f]/.test(c)||r.startsWith(c)&&n(c)),i=[...new Set(s)].filter((c,l,u)=>!u.some(d=>d!==c&&d.startsWith(c)));if(i.length>1)return{status:"unverifiable",observedRevision:null,evidence:UC(`The answer names more than one revision: ${i.join(", ")}`)};let[o]=i;return o?{status:r.startsWith(o)?"verified":"mismatch",observedRevision:o,evidence:jbe(e.body,o)}:{status:"unverifiable",observedRevision:null,evidence:UC(e.body)}}async function $C(t,e=fetch){try{let r=AbortSignal.timeout(xlt),n=new URL(t).origin,s=new URL(t);for(let i=0;;i+=1){let o=await e(s,{redirect:"manual",signal:r}),a=o.status>=300&&o.status<400?o.headers.get("location"):null;if(a){let l=new URL(a,s);if(l.origin!==n)return{error:`${t} redirects to another origin (${l.origin})`};if(i>=zbe)return{error:`${t} redirects more than ${zbe} times`};s=l;continue}let c=await o.text();return o.ok?{body:c}:{error:`${t} answered ${o.status}: ${c.trim()}`}}}catch(r){let n=r instanceof Error&&r.cause instanceof Error?`: ${r.cause.message}`:"";return{error:`${t} could not be read: ${r instanceof Error?r.message:String(r)}${n}`}}}var ZYt=new Set(["version_endpoint","api"]);function GC(t){return(t?.components??[]).filter(e=>!!e.repository&&!!e.expectedRevision)}function Yk(t){return GC(t.sharedEnvironment).filter(e=>!e.revisionUrl)}async function Tlt(t,e,r=[]){let{name:n,url:s}=t;if(!t.versionUrl)return{name:n,url:s,version:null,evidence:"No version URL is configured."};let i=ir(await $C(t.versionUrl,e),r);if("error"in i)return{name:n,url:s,version:null,evidence:UC(i.error)};let o=i.body.split(/\r?\n/).map(a=>a.trim()).find(Boolean);return{name:n,url:s,version:o?o.slice(0,vlt):null,evidence:UC(o??"")}}var Wbe=(t,e)=>!!t&&!!e&&t.toLowerCase()===e.toLowerCase(),Ybe=(t,e)=>t.name===e.name&&Wbe(t.repository,e.repository);async function klt(t,e,r){let{frozen:n,mergeCommit:s,mergedHead:i}=e;return!s||!i?"not_contained":i.toLowerCase()===n.toLowerCase()?"contained":r?.commitContains?r.commitContains({repository:t,ancestor:n,descendant:i}):"unknown"}async function Vbe(t,e,r){let n=e.observedRevision;if(e.status!=="mismatch"||!n||!t.acceptedRevisions)return e;let{frozen:s,mergeCommit:i,mergedHead:o}=t.acceptedRevisions,a=await klt(t.repository,t.acceptedRevisions,r),c=[s,...i&&a==="contained"?[i]:[]],l=f=>`${f===s?"the frozen revision":"the merge commit"} ${rs(f)}`,u=(f,A)=>({status:f,observedRevision:n,evidence:Wk(`${A} (${e.evidence})`)}),d=c.find(f=>f.toLowerCase().startsWith(n));if(d)return u("verified",`observed ${rs(n)} is ${l(d)}`);if(!r?.commitContains)return u("unverifiable",`could not tell whether observed ${rs(n)} contains ${c.map(rs).join(" or ")}: this run cannot compare commits`);let p=[];for(let f of c){let A=await r.commitContains({repository:t.repository,ancestor:f,descendant:n});if(A==="contained")return u("verified",`observed ${rs(n)} contains ${l(f)}`);A==="unknown"&&p.push(f)}return p.length?u("unverifiable",`could not tell whether observed ${rs(n)} contains ${p.map(rs).join(" or ")}: GitHub did not answer the compare`):a==="unknown"&&o?u("unverifiable",`could not tell whether the merged head ${rs(o)} contains ${rs(s)}: GitHub did not answer the compare`):u("mismatch",`observed ${rs(n)} does not contain ${c.map(rs).join(" or ")}`)}async function Jk(t,e,r,n=[],s){let i=(a,c)=>qC(a,ir(c,n));return{components:await Promise.all(GC(t).map(async a=>{let c={name:a.name,repository:a.repository,url:a.url,expectedRevision:a.expectedRevision};if(a.revisionUrl)return{...c,source:"probe",...await Vbe(a,i(a.expectedRevision,await $C(a.revisionUrl,r)),s)};let l=e.find(d=>d.component===a.name),u=i(a.expectedRevision,l?{body:l.output}:{error:"Deploy cited no check of its deployed revision."});return{...c,source:"agent",...await Vbe(a,u,s)}})),dependencies:await Promise.all(t.dependencies.map(a=>Tlt(a,r,n)))}}async function Nlt(t,e,r,n=[]){let s=await Promise.all(e.components.map(async i=>{let o=t.components.find(u=>Ybe(u,i)),a=i.observedRevision?.toLowerCase();if(!a||!o?.revisionUrl)return i;let c=ir(await $C(o.revisionUrl,r),n),l=qC(i.expectedRevision,c);if(!l.observedRevision){let u="error"in c?"second read failed":"second read names no one commit",d=`first read ${rs(i.observedRevision??a)}; ${u}: ${l.evidence}`;return{...i,status:"unverifiable",observedRevision:null,evidence:Wk(d)}}return l.observedRevision.startsWith(a)||a.startsWith(l.observedRevision)?i:{...i,status:"unverifiable",observedRevision:l.observedRevision,evidence:Wk(`changed from ${i.observedRevision} to ${l.observedRevision} during the run`)}}));return{...e,components:s}}async function Jbe(t,e){let r=t.inputs.sharedEnvironment,n=ne(t,`${la}.json`);if(!t.inputs.appRunning||!r||!n)return;let s=await Nlt(r,n,e,t.secretValues??[]);pt(t,la,ir(s,t.secretValues??[]),[])}function HC(t){return GC(t).length>0||(t?.dependencies.length??0)>0}function bV(t){let e=t.inputs?.sharedEnvironment;if(!HC(e))return;let r=ne(t,`${la}.json`);if(r)return{components:Zbe(e,r.components),dependencies:r.dependencies};let n="Not checked: deploy did not complete.";return{components:GC(e).map(s=>Kbe(s,n)),dependencies:e.dependencies.map(s=>({name:s.name,url:s.url,version:null,evidence:n}))}}var Kbe=(t,e)=>({name:t.name,repository:t.repository,url:t.url,expectedRevision:t.expectedRevision,observedRevision:null,status:"unverifiable",source:t.revisionUrl?"probe":"agent",evidence:e});function Zbe(t,e){let r=new Set(e.map(s=>s.name.toLowerCase())),n=GC(t).filter(s=>s.touched&&!r.has(s.name.toLowerCase()));return[...e,...n.map(s=>Kbe(s,"Not checked: the run recorded no read of it."))]}function kA(t){return(bV(t)?.components??[]).filter(e=>e.status!=="verified")}function wV(t,e,r){if(!t.appRunning||r===!1)return[];let n=(t.sharedEnvironment?.components??[]).filter(s=>s.touched);return Zbe(t.sharedEnvironment,e?.components??[]).filter(s=>s.status!=="verified"&&n.some(i=>Ybe(i,s)))}function Xbe(t){let e=r=>{let n=r.observedRevision?`runs ${rs(r.observedRevision)}`:"no revision could be read";return`${r.name} (${r.repository}) must run ${rs(r.expectedRevision)}, but ${n}: ${r.evidence}`};return t.length?`the Test Environment does not verifiably run the change: ${t.map(e).join("; ")}`:void 0}function Kk(t){return(t?.components??[]).filter(e=>!!e.repository&&!e.expectedRevision)}function ewe(t,e=!1){return`${t.name}: ${t.repository} is not one of the run's sources, so its revision cannot be verified and ${twe(e)}`}var twe=t=>t?"runtime tests against it do not validate this change":"no runtime test ran against it";function rwe(t,e=!1){let r=rs(t.expectedRevision),n=t.status==="mismatch"?`the shared environment runs ${t.repository} at ${t.observedRevision}, not ${r}`:`could not verify that the shared environment runs ${t.repository} at ${r}`;return`${t.name}: ${n}, so ${twe(e)}`}var _lt=/^\s*(POST|PUT|PATCH|DELETE)\s/i,yV=t=>t.mutates===!0;function ih(t){return(t?.components??[]).filter(e=>!!e.repository)}function Ri(t){let e=t.sharedEnvironment;return!!e&&ih(e).length>0&&!e.allowMutation&&!t.planOnly}function Plt(t){let e=n=>_lt.test(n.target)||yV(n),r=[...t.generate.filter(e).map(n=>({id:n.id,target:n.target})),...t.maintenance.filter(yV).map(n=>({id:n.test}))];return{...t,generate:t.generate.filter(n=>!e(n)),surfaces:Vk(t.surfaces,new Set(r.map(n=>n.id)),"withheld because they change a shared environment the policy protects"),maintenance:t.maintenance.filter(n=>!yV(n)),withheld:r}}function NA(t,e){return e&&Ri(t)?Plt(e):e}function Zk(t){return ne(t,"recommend.json")?.withheld??[]}function nwe(t){return`${t.id}${t.target?` (${t.target})`:""}: needs a shared-environment mutation the policy does not allow`}var qA=j(require("fs")),UA=j(require("path"));function Ht(t,e=[]){let r=t.trim();if(!r)return{error:"session produced no output"};let n=c=>{try{let l=JSON.parse(c);return typeof l=="object"&&l!==null&&!Array.isArray(l)?l:void 0}catch{return}},s=n(r);if(s!==void 0)return{value:s};let i;if(r.startsWith("{")&&r.endsWith("}"))try{JSON.parse(r)}catch(c){i=c instanceof Error?c.message:String(c)}let o=[...r.matchAll(/```(?:json)?\s*\n([\s\S]*?)```/g)];for(let c=o.length-1;c>=0;c--){let l=n(o[c][1].trim());if(l!==void 0)return{value:l}}let a;for(let c=r.indexOf("{");c!==-1;c=r.indexOf("{",c+1)){let l=0,u=!1,d=!1;for(let p=c;p<r.length;p++){let f=r[p];if(d){d=!1;continue}if(f==="\\"){d=u;continue}if(f==='"'){u=!u;continue}if(!u){if(f==="{")l++;else if(f==="}"&&(l--,l===0)){let A=n(r.slice(c,p+1));A!==void 0&&Object.keys(A).length>0&&(a=A,c=p);break}}}}return i&&(a===void 0||Object.keys(a).length<3)?{error:`final message is not valid JSON \u2014 ${i}. Most often an unescaped double quote inside a string (e.g. in "summary" or "evidence"): escape it as \\" or use single quotes in prose`}:a!==void 0?{value:a}:i?{error:`final message is not valid JSON \u2014 ${i}. Most often an unescaped double quote inside a string (e.g. in "summary" or "evidence"): escape it as \\" or use single quotes in prose`}:{error:`no parseable JSON object found in session output \u2014 the final message was: "${Qlt(an(r,e))}"`}}var swe=240;function Qlt(t){let e=t.replace(/\s+/g," ").trim();return e.length<=swe?e:`\u2026${e.slice(-swe)}`}function Jt(t,e=0,r=new Set){return zC(t,e,r)}var iwe=t=>" ".repeat(t);function zC(t,e,r){let n=Dlt(t);switch(n._def.typeName){case"ZodObject":{let i=n.shape,o=Object.keys(i).filter(c=>!r.has(c)&&!i[c].description?.startsWith("[derived]"));return o.length===0?"{}":`{
217
217
  ${o.map((c,l)=>{let u=i[c],d=u.isOptional()?" (optional)":"",p=u.description?` // ${u.description}`:"",f=zC(u,e+2,r);return`${iwe(e+2)}"${c}": ${f}${l<o.length-1?",":""}${d}${p}`}).join(`
218
218
  `)}
219
219
  ${iwe(e)}}`}case"ZodArray":{let i=n.element;return`[ ${zC(i,e,r)}, \u2026 ]`}case"ZodEnum":return n.options.map(i=>JSON.stringify(i)).join(" | ");case"ZodNativeEnum":return Object.values(n.enum).map(i=>JSON.stringify(i)).join(" | ");case"ZodLiteral":return JSON.stringify(n.value);case"ZodString":return'"\u2026"';case"ZodNumber":return"<number>";case"ZodBoolean":return"true | false";case"ZodNull":return"null";case"ZodUnion":return n.options.map(i=>zC(i,e,r)).join(" | ");case"ZodRecord":return`{ "<key>": ${zC(n.valueSchema,e,r)} }`;default:return"<value>"}}function Dlt(t){let e=t;for(;;){let r=e._def;if(r.typeName==="ZodOptional"||r.typeName==="ZodNullable"||r.typeName==="ZodDefault"){if(r.typeName==="ZodNullable")return g.union([r.innerType,g.null()]);e=r.innerType}else if(r.typeName==="ZodEffects")e=r.schema;else return e}}function Olt(t){return t.issues.map(e=>{let r=e.path.map(s=>typeof s=="number"?`[${s}]`:`.${s}`).join("").replace(/^\./,""),n=r||"output";if(!/^(Expected |Required$|Invalid |String must|Array must|Number must)/.test(e.message))return`${n} ${e.message}`;switch(e.code){case"invalid_type":return r?e.expected==="object"?`${n} must be an object`:e.received==="undefined"?`${n} is required`:`${n} must be ${e.expected}, got ${e.received}`:"output is not a JSON object";case"invalid_enum_value":{let s=JSON.stringify(e.received),i=e.options.find(a=>typeof a=="string"&&typeof e.received=="string"&&e.received.startsWith(a)),o=i?` \u2014 you sent ${s}; the value must be exactly ${JSON.stringify(i)}, with any qualifier moved to a field that takes free text`:` \u2014 you sent ${s}`;return`${n} must be one of: ${e.options.join(", ")}${o}`}case"invalid_literal":return`${n} must be ${JSON.stringify(e.expected)}`;case"too_small":return e.type==="string"?`${n} must be a non-empty string`:`${n} must have at least ${e.minimum} item(s)`;case"unrecognized_keys":return`${n} has unknown key(s): ${e.keys.join(", ")}`;default:return`${n}: ${e.message}`}})}function br(t,e){let r=t.safeParse(e);if(r.success)return{value:r.data,errors:[]};let n=(i,o)=>o.reduce((a,c)=>a&&typeof a=="object"?a[c]:void 0,i),s=r.error.issues.filter(i=>i.path.length&&n(e,i.path)===null);if(s.length===r.error.issues.length)try{let i=t.safeParse(s.reduce((o,{path:a})=>owe(o,a),e));if(i.success)return{value:i.data,errors:[]}}catch{}return{errors:Olt(r.error)}}function owe(t,e){if(!e.length||!t||typeof t!="object")return t;let[r,...n]=e,s=Array.isArray(t)?t.slice():{...t};return n.length?s[r]=owe(s[r],n):delete s[r],s}function _A(t,e,r){let n=br(t,r),s=r&&typeof r=="object"&&!Array.isArray(r)?r:void 0,i=[...n.errors,...s?e(s):[]];return i.length?{errors:i}:{value:n.value,errors:[]}}var awe=j(require("path"));var CV="outputs/preflight.json",oh="pr-diff.txt";function Qd(t,e){return[...t.changedFiles.map(r=>({repository:e,path:r.path})),...(t.relatedChanges??[]).flatMap(r=>r.changedFiles.map(n=>({repository:r.repository,path:n.path})))]}function PA(t,e,r){return t.some(n=>n.path===r&&n.repository.toLowerCase()===e.toLowerCase())}function cn(t){if(t.outputsDir)return Nc(awe.join(t.outputsDir,"preflight.json"))}var nN=j(require("path"));var lwe=require("child_process"),eN=j(require("fs")),QA=j(require("path"));Rd();var tN="ci-evidence.json",Xk=(t,e)=>(0,lwe.execFileSync)("git",e,{cwd:t,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim(),Mlt=/^Merge ([0-9a-f]{40}) into [0-9a-f]{40}$/;function Flt(t){try{let e=Xk(t,["rev-parse","HEAD"]);if(Xk(t,["rev-list","--parents","-n","1","HEAD"]).split(/\s+/).slice(1).length===2){let n=Mlt.exec(Xk(t,["log","-1","--format=%s","HEAD"]));if(n)return n[1]}return e}catch{return}}function rN(t){let e="";try{e=Xk(t,["remote","get-url","origin"])}catch{}let r=/[:/]([A-Za-z0-9._-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?\/?$/.exec(e);return r&&!e.startsWith("/")&&!e.startsWith(".")?`${r[1]}/${r[2]}`:`local/${QA.basename(QA.resolve(t)).replace(/[^A-Za-z0-9._-]/g,"-")||"repo"}`}var Llt=new Set(Object.values(Td));function Ult(t){let e=[];for(let r of t??[]){let n=r.trim();if(!n)continue;let s=n.lastIndexOf("="),i=s>0?n.slice(s+1).trim():"",o=Llt.has(i),c=(o?n.slice(0,s).trim():n).split("*").map(l=>l.replace(/[.+?^${}()|[\]\\]/g,"\\$&")).join(".*");e.push({pattern:new RegExp(`^${c}$`,"i"),kind:o?i:"ci_check"})}return e}var qlt=new Set(["failure","timed_out","action_required","error","startup_failure"]);function cwe(t,e){let r=new Map(e.revisions.map(s=>[s.repository.toLowerCase(),s])),n=[];for(let s of t){if(s.name.startsWith(CC))continue;let i=r.get((s.repository??e.primary).toLowerCase());if(!i)continue;let o=e.trusted.find(l=>l.pattern.test(s.name)),a=s.conclusion??s.status,c=o?s.headSha.toLowerCase()!==i.revision.toLowerCase()?"stale":s.status!=="completed"?"pending":s.conclusion==="success"?"accepted":qlt.has(s.conclusion??"")?"failing":"inconclusive":"untrusted";n.push({id:`ci-${n.length+1}`,repository:i.repository,revision:i.revision,checkSha:s.headSha,name:s.name,kind:o?.kind??"ci_check",status:c,conclusion:a,reference:s.url||`${i.repository}@${s.headSha.slice(0,12)} ${s.name}`,summary:(s.summary||`${s.name}: ${a}`).slice(0,300)})}return n}var $lt=g.object({checks:g.array(g.object({repository:g.string().optional(),name:g.string().min(1),headSha:g.string().regex(/^[0-9a-f]{40}$|^[0-9a-f]{64}$/i),status:g.string().default("completed"),conclusion:g.string().nullable().optional(),url:g.string().optional(),summary:g.string().optional()}))});function Glt(t){let e=$lt.safeParse(JSON.parse(eN.readFileSync(t,"utf-8")));if(!e.success)throw new Error(`${t} is not a CI evidence file: ${e.error.issues[0]?.message??"invalid"}`);return e.data.checks}function Hlt(t){let e=[{path:t.inputs.repositoryPath,slug:t.inputs.repositorySlug},...(t.inputs.relatedRepos??[]).map(n=>({path:n.path,slug:n.slug}))],r=[];for(let n of e){let s=Flt(n.path);s&&r.push({repository:n.slug??rN(n.path),revision:s})}return r}async function uwe(t){let e=Hlt(t),r=e[0]?.repository??rN(t.inputs.repositoryPath),n=Ult(t.inputs.trustedChecks),s;try{if(t.inputs.ciEvidenceFile){let i=Glt(t.inputs.ciEvidenceFile);s={source:"file",revisions:e,items:cwe(i,{revisions:e,primary:r,trusted:n})}}else if(t.platform?.listCommitChecks){let i=[];for(let o of e)i.push(...await t.platform.listCommitChecks(o)??[]);s={source:"platform",revisions:e,items:cwe(i,{revisions:e,primary:r,trusted:n})}}else s={source:"none",revisions:e,items:[],note:"this platform keeps no CI results"}}catch(i){s={source:"none",revisions:e,items:[],note:`CI results could not be read: ${i instanceof Error?i.message:String(i)}`}}return s.items.length>0&&n.length===0&&(s.note="no trustedChecks were configured, so no CI result counts as evidence"),eN.writeFileSync(QA.join(t.outputsDir,tN),JSON.stringify(s,null,2)+`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/testbot-core",
3
- "version": "0.13.0-v3.74",
3
+ "version": "0.13.0-v3.75",
4
4
  "description": "Skyramp Testbot engine: AI-powered deterministic test generation, execution and maintenance",
5
5
  "main": "dist/main.js",
6
6
  "//files": "An explicit allowlist, never a glob. `dist/` is gitignored, so without this key npm's .gitignore fallback would publish a package with no engine in it; with a glob it would publish the sourcemaps, whose sourcesContent embeds every src/*.ts verbatim. eval-entry.js is a development entry and must not ship. dist/VERSION.json exists only in a release-engine.yml build. assets/gen-reference/ is the staged codegen reference corpus, which generate.ts finds at ../assets from dist/.",