grooph 0.4.1 → 0.5.0

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.
Files changed (57) hide show
  1. package/README.md +33 -31
  2. package/THIRD-PARTY-NOTICES.md +5 -1
  3. package/dist/app/assets/App-CT9KxzfQ.css +1 -0
  4. package/dist/app/assets/App-D1pDFbEY.js +5 -0
  5. package/dist/app/assets/EmbedApp-CTausQWY.js +1 -0
  6. package/dist/app/assets/ExportPanel-CbRH4C69.js +8 -0
  7. package/dist/app/assets/Import-DF0XLxRI.js +1 -0
  8. package/dist/app/assets/SketchView-BjeUHG4X.js +143 -0
  9. package/dist/app/assets/{brakes-BJPDrrJT.js → brakes-B9b3hDX8.js} +1 -1
  10. package/dist/app/assets/{builtins-D_22fKRF.js → builtins-DzyPaYdd.js} +1 -1
  11. package/dist/app/assets/{compile-BAvi-rd0.js → compile-DL2budwP.js} +8 -8
  12. package/dist/app/assets/{front-BRl7rl-u.js → front-OxfL-OaD.js} +1 -1
  13. package/dist/app/assets/full-C0asYORc.js +1 -0
  14. package/dist/app/assets/graph-more-Dn_hNa20.js +2 -0
  15. package/dist/app/assets/graph-stage-CwNePnN4.js +4 -0
  16. package/dist/app/assets/graph-views-CmkQ41zC.js +2 -0
  17. package/dist/app/assets/{index-CeaKwKuU.js → index-B5ZkSF4L.js} +2 -2
  18. package/dist/app/assets/mermaid-read-cyqJ32v-.js +17 -0
  19. package/dist/app/assets/{plan-templates-BQu8G2sX.js → plan-templates-u2fF3GnS.js} +1 -1
  20. package/dist/app/assets/runs-BA5HKtsx.js +1 -0
  21. package/dist/app/assets/screens-CMMuexid.js +16 -0
  22. package/dist/app/assets/share-DV3wsAsJ.js +8 -0
  23. package/dist/app/assets/site-looks.v1.css +223 -0
  24. package/dist/app/assets/space-Cuy4YqyZ.js +1 -0
  25. package/dist/app/assets/styles-Dlp-yYlE.css +1 -0
  26. package/dist/app/assets/templates-DbAhWvP6.js +2 -0
  27. package/dist/app/assets/{themes-DtOBrLk0.js → themes-C34TrvOJ.js} +1 -1
  28. package/dist/app/assets/{units-DOIUgOIU.js → units-DlniUjfH.js} +1 -1
  29. package/dist/app/assets/{views-CLwg5VNv.js → views-CFqRShXD.js} +2 -1
  30. package/dist/app/grooph-app.json +1 -1
  31. package/dist/app/index.html +14 -11
  32. package/dist/app/llms.txt +6 -7
  33. package/dist/app/manifest.webmanifest +1 -1
  34. package/dist/app/og.png +0 -0
  35. package/dist/app/routes.json +42 -33
  36. package/dist/app/sw.js +7 -2
  37. package/dist/browser/grooph.d.ts +44 -0
  38. package/dist/browser/grooph.global.js +7 -0
  39. package/dist/browser/grooph.js +7 -0
  40. package/dist/bundle/grooph.js +6734 -2536
  41. package/hooks/grooph-event.mjs +163 -14
  42. package/package.json +14 -6
  43. package/dist/app/assets/App-48y1Ec5B.js +0 -5
  44. package/dist/app/assets/App-Cv1auMeh.css +0 -1
  45. package/dist/app/assets/EmbedApp-390Z2d4x.js +0 -1
  46. package/dist/app/assets/ExportPanel-Ca3wBB38.js +0 -8
  47. package/dist/app/assets/Import-ByMI7Uz9.js +0 -1
  48. package/dist/app/assets/graph-more-393HTgQE.js +0 -2
  49. package/dist/app/assets/graph-stage-BkrQGQ-z.js +0 -4
  50. package/dist/app/assets/graph-views-COQF_QTQ.js +0 -2
  51. package/dist/app/assets/runs-DcjRi7S6.js +0 -1
  52. package/dist/app/assets/screens-aIjMSzZg.js +0 -16
  53. package/dist/app/assets/share-BzIzB4EY.js +0 -8
  54. package/dist/app/assets/space-DWgrlnfB.js +0 -1
  55. package/dist/app/assets/styles-BA1aVO9R.css +0 -1
  56. package/dist/app/assets/templates-CoNTzuuz.js +0 -2
  57. package/dist/app/demo/run.txt +0 -1
@@ -1 +1 @@
1
- import{t as e}from"./index-CeaKwKuU.js";import{Kt as t,Ut as n,Yt as r}from"./share-BzIzB4EY.js";var i=e=>typeof e.when==`object`?e.when.verdict:e.when??`always`;function a(e){let t=new Map(e.nodes.map(e=>[e.id,e.kind])),n=new Set(e.nodes.filter(e=>e.kind===`stop`&&e.outcome===`halt`).map(e=>e.id)),a=new Set(e.nodes.filter(r).map(e=>e.id)),o=e.edges.map(e=>({from:e.from,to:e.to,person:e.approval===!0||t.get(e.from)===`human-gate`,edge:e.id,when:i(e)}));for(let t of e.loops)for(let e of t.stops){if(e.then===void 0)continue;let r=e.kind===`max-iterations`||e.kind===`budget`||e.kind===`human`,i=r&&n.has(e.then),s=e.kind===`bar-passed`?t.members.filter(e=>a.has(e)):[];for(let n of t.members)o.push({from:n,to:e.then,person:e.kind===`human`,loop:t.id,...r?{fires:r}:{},...i?{escalates:i}:{},...s.length>0?{verdictOf:s}:{}})}return o}var o=e=>`${e.loop}\n${e.to}`;function s(e,t){if(t===`every`)return e.person;if(`approval`in t)return e.edge===t.approval;if(`critic`in t&&(e.escalates||e.fires&&t.stops?.has(o(e)))||`critic`in t&&e.verdictOf?.includes(t.critic)&&(t.when===void 0||t.when===`pass`))return!0;let n=`gate`in t?t.gate:t.critic;return e.edge!==void 0&&e.from===n&&(t.when===void 0||e.when===t.when)}function c(e){let t=new Set(e.loops.flatMap(e=>e.back));return e.nodes.filter(n=>!e.edges.some(e=>e.to===n.id&&!t.has(e.id))).map(e=>e.id)}function l(e,t,n){let r=new Set(e.nodes.map(e=>e.id)),i=new Map;for(let t of a(e))n!==void 0&&s(t,n)||!r.has(t.from)||!r.has(t.to)||(i.get(t.from)??i.set(t.from,[]).get(t.from)).push(t.to);let o=new Set(t),c=[...o];for(let e=c.pop();e!==void 0;e=c.pop())for(let t of i.get(e)??[])o.has(t)||(o.add(t),c.push(t));return o}var u=(e,t)=>l(e,c(e),t);function d(e,t){let n=new Map(t.nodes.map(e=>[e.id,e])),s=new Set(t.edges.filter(e=>e.approval===!0).map(e=>e.id)),c=t=>[...new Set(e.edges.filter(e=>e.from===t).map(i))],l=[`every`],u=new Set(a(e).filter(e=>e.fires).map(o));for(let t of e.nodes)t.kind===`human-gate`&&n.get(t.id)?.kind===`human-gate`&&l.push({gate:t.id},...c(t.id).map(e=>({gate:t.id,when:e})));for(let t of e.edges)t.approval===!0&&s.has(t.id)&&l.push({approval:t.id});for(let t of e.nodes){let e=n.get(t.id);if(r(t)&&e&&r(e)&&l.push({critic:t.id},...c(t.id).map(e=>({critic:t.id,when:e}))),t.kind===`check`&&e?.kind===`check`)for(let e of[{check:!0},{check:!0,stops:u}])l.push({critic:t.id,...e},...c(t.id).map(n=>({critic:t.id,when:n,...e})))}return l}function f(e){if(e===`every`)return`a person`;if(`approval`in e)return`the approval on "${e.approval}"`;if(`gate`in e)return e.when===void 0?`the human gate "${e.gate}"`:`"${e.when}" at the human gate "${e.gate}"`;let t=e.check?`check`:`critic`;return e.when===void 0?`the ${t} "${e.critic}"`:`"${e.when}" from the ${t} "${e.critic}"`}var p=(e,t)=>JSON.stringify(e)===JSON.stringify(t),m=(e,t)=>e!==void 0&&(e===t||e.startsWith(`${t}; `)||e.endsWith(`; ${t}`)||e.includes(`; ${t}; `)),h=e=>e.map(e=>`"${e}"`).join(`, `),g=e=>e?.kind===`agent`?e.irreversible??[]:[],_=e=>e.kind===`max-iterations`||e.kind===`budget`||e.kind===`human`,v={dispatches:`dispatch`,minutes:`minute`,turns:`turn`,tokens:`token`,rounds:`round`},y=(e,t)=>`${e} ${e===1?v[t]??t:t}`,b=(e,t)=>t===``?`${e}`:y(e,t);function x(e){let t=new Map(e.nodes.map(e=>[e.id,e]));return e=>{if(e.then===void 0)return!0;let n=t.get(e.then);return n?.kind===`human-gate`||n?.kind===`stop`&&n.outcome===`halt`}}function S(e,t){let n=x(e),r=new Map,i=(e,t)=>e===void 0?t:Math.min(e,t);for(let e of t)for(let t of e.stops){let[e,a,o,s]=t.kind===`max-iterations`?[`cap`,`the round cap`,``,t.n]:t.kind===`budget`?[`budget ${t.measure}`,`the budget`,t.measure,t.limit]:t.kind===`human`?[`human`,`the stop where a person is asked`,``,t.every??1]:[void 0,``,``,0];if(e===void 0)continue;let c=r.get(e)??r.set(e,{name:a,unit:o,leads:new Set}).get(e);c.any=i(c.any,s),n(t)?c.halt=i(c.halt,s):(c.lead=i(c.lead,s),c.leads.add(t.then))}return r}function C(e,t){let n=[],r=e=>e.lead!==void 0&&(e.halt===void 0||e.lead<=e.halt);for(let[i,a]of e){let e=t.get(i),o=i===`human`;if(e?.any===void 0)n.push(o?`removes the stop where a person is asked`:`removes ${a.name} (${b(a.any,a.unit)})`);else if(e.any>a.any)n.push(o?`a person would be asked every ${e.any} rounds, not every ${a.any}`:`raises ${a.name} from ${a.any} to ${b(e.any,a.unit)}`);else if(a.halt!==void 0&&e.halt===void 0)n.push(`${a.name} (${b(a.halt,a.unit)}) would no longer halt the run`);else if(a.halt!==void 0&&e.halt>a.halt)n.push(`${a.name} that halts the run would rise from ${a.halt} to ${b(e.halt,a.unit)}`);else if(a.halt!==void 0&&!r(a)&&r(e))n.push(`${o?`a stop that asks a person`:a.name} of ${b(e.lead,a.unit)} that leads on to ${h([...e.leads])} would fire ${e.lead<e.halt?`before`:`as soon as`} the one of ${b(e.halt,a.unit)} that halts the run`);else if(r(e)){let t=[...e.leads].filter(e=>!a.leads.has(e));t.length>0&&n.push(`${a.name} would lead on to ${h(t)}${a.leads.size>0?`, not to ${h([...a.leads])}`:``}`)}}return n}function w(e){switch(e.kind){case`max-iterations`:return`the round cap of ${e.n}`;case`budget`:return`the budget of ${y(e.limit,e.measure)}`;case`human`:return(e.every??1)===1?`the stop where a person is asked`:`the stop where a person is asked every ${y(e.every,`rounds`)}`;case`diminishing-returns`:return`the stop on diminishing returns over ${y(e.rounds,`rounds`)}`;case`evidence-invalid`:return`the stop on evidence invalid for ${y(e.rounds,`rounds`)}`;default:return`the stop on "bar passed"`}}var T=e=>e.kind===`max-iterations`?e.n:e.kind===`budget`?e.limit:e.kind===`human`?e.every??1:e.kind===`bar-passed`?void 0:e.rounds,E=e=>e.kind===`budget`?`budget ${e.measure}`:e.kind===`diminishing-returns`?`${e.kind} ${JSON.stringify([e.metric??null,e.threshold??null])}`:e.kind,D=(e,t)=>n=>n.kind===`human`?!1:n.kind===`bar-passed`?!t&&(n.then===void 0||!e(n)):n.then!==void 0&&!e(n);function O(e){let t=e=>Number.isFinite(e)?Math.max(1,Math.ceil(e)):1;switch(e.kind){case`max-iterations`:return{sort:`cap`,from:t(e.n)};case`human`:return{sort:`person`,every:t(e.every??1)};case`budget`:return{sort:`counted`,key:`budget ${e.measure}`,size:e.limit,from:1,lasting:!0};case`diminishing-returns`:return{sort:`counted`,key:`no progress ${JSON.stringify([e.metric??null,e.threshold??null])}`,size:e.rounds,from:t(e.rounds),lasting:!1};case`evidence-invalid`:return{sort:`counted`,key:`invalid evidence`,size:e.rounds,from:t(e.rounds),lasting:!1};default:return{sort:`counted`,key:`bar passed`,size:0,from:1,lasting:!1}}}function k(e){let t=e.map(O),n=[],r=[],i=new Map,[a,o,s,c]=[!1,1/0,1/0,1/0];t.forEach((e,t)=>{n.push(a),r.push(o),e.sort===`person`?(i.has(e.every)||i.set(e.every,t),a||=e.every===1,s=Math.min(s,e.every)):e.sort===`cap`&&(o=Math.min(o,e.from),s>e.from&&(c=Math.min(c,e.from)))});let l=new Map,u=e=>{let n=l.get(e);if(!n){let r=1/0;n=t.map(t=>{let n=r;return t.sort===`counted`&&t.key===e&&(r=Math.min(r,t.size)),n}),l.set(e,n)}return n},d=new Map;return{timing:t,always:n,capAhead:r,over:c,person:i,divides:e=>{let t=d.get(e);if(t===void 0){t=1/0;for(let[n,r]of i)e%n===0&&(t=Math.min(t,r));d.set(e,t)}return t},least:u}}function A(e,t,n,r){let[i,a]=[k(e),k(n)],o=i.timing.flatMap((e,t)=>e.sort===`cap`?[{from:e.from,at:t}]:[]).sort((e,t)=>e.from-t.from),s=[];return n.forEach((n,c)=>{let l=a.timing[c];if(l.sort===`person`||!r(n)||a.always[c])return;let[u,d]=[l.from,Math.min(a.over,a.capAhead[c]-1)];if(u>d||l.sort===`counted`&&!(a.least(l.key)[c]>l.size))return;let f=[],p=1/0;for(let e of i.timing)f.push(p),e.sort===`person`&&!(a.divides(e.every)<c)&&(p=Math.min(p,e.every));let m=u;if(l.sort===`counted`){let e=i.timing.findIndex(e=>e.sort===`counted`&&e.key===l.key&&e.size<=l.size);e>=0&&(m=Math.max(m,f[e]))}for(let e of o)e.from<=m&&m<f[e.at]&&(m=f[e.at]);let h;for(let[r,o]of e.entries()){let e=i.timing[r];if(!t(o)||i.always[r]||e.sort===`person`&&i.divides(e.every)<r)continue;let[f,p]=[e.sort===`person`?e.every:e.from,Math.min(i.over,i.capAhead[r]-1)];if(f>p||e.sort===`counted`&&!(i.least(e.key)[r]>e.size)||l.sort===`counted`&&l.lasting&&!(i.least(l.key)[r]>l.size))continue;let g=(t,n)=>t<=n&&(e.sort!==`person`||Math.ceil(t/e.every)*e.every<=n),_=g(Math.max(u,f),Math.min(d,p))&&!(e.sort===`person`&&a.divides(e.every)<c)&&!(l.sort===`counted`&&!(i.least(l.key)[r]>l.size))&&!(e.sort===`counted`&&!(a.least(e.key)[c]>e.size));if(Number.isFinite(m)&&m<=d&&g(Math.max(f,m+1),p)){e.sort===`person`&&_?s.push({at:c,from:r,lead:n,halt:o,before:!1}):s.push({at:c,from:r,lead:n,halt:o,before:!0,...e.sort===`person`?{again:m>=e.every}:{}});return}_&&(h??=r)}h!==void 0&&s.push({at:c,from:h,lead:n,halt:e[h],before:!1})}),s}var j=e=>e.edge??`${e.loop} → ${e.to}`;function M(e,t,n){let r=new Set(t.back),i=new Set(e.nodes.filter(e=>e.kind===`human-gate`).map(e=>e.id)),o=a(e).filter(e=>e.from!==e.to&&(e.edge===void 0||!r.has(e.edge))&&(!e.person||n.has(j(e)))),s=n=>n.edge===void 0?[j(n)]:e.loops.filter(e=>e.id!==t.id&&e.back.includes(n.edge)).map(e=>e.id),c=(e,t)=>{let n=new Set(e),r=[...n];for(let e=r.pop();e!==void 0;e=r.pop())for(let i of t(e))n.has(i)||r.push((n.add(i),i));return n},l=o.filter(e=>e.loop===t.id&&t.members.includes(e.to)&&!i.has(e.to)),u=new Map(l.map(e=>[j(e),e])),d=new Map;for(let e of t.members){let t=c([e],e=>o.filter(t=>t.from===e).map(e=>e.to)),n=c([e],e=>o.filter(t=>t.to===e).map(e=>e.from)),r=new Set(l.map(j));for(let e of o)if(t.has(e.from)&&n.has(e.to)){u.set(j(e),e);for(let t of s(e))r.add(t)}d.set(e,r)}return{ways:u,closers:d}}function N(e,t){let n=[],i=[],o=new Set(t.nodes.map(e=>e.id)),s=new Set(e.nodes.map(e=>e.id)),c=a(e),u=a(t),d=new Set(t.nodes.filter(e=>[...l(t,u.filter(t=>t.from===e.id&&t.to!==e.id).map(e=>e.to))].includes(e.id)||u.some(t=>t.edge!==void 0&&t.from===e.id&&t.to===e.id)).map(e=>e.id)),f=new Map(t.edges.map(e=>[e.id,e])),m=new Map(t.loops.map(e=>[e.id,e])),g=new Map(e.loops.map(e=>[e.id,e])),v=new Map(e.edges.map(e=>[e.id,e])),y=new Set(e.nodes.filter(e=>r(e)&&t.nodes.some(t=>t.id===e.id&&r(t))).map(e=>e.id));for(let r of e.loops){if(!(r.stops.some(_)||r.bar!==void 0))continue;let a=m.get(r.id);a||n.push({why:`removes a loop with its stops and its bar`,at:[`loop:${r.id}`]});let l=[...new Set(r.stops.flatMap(e=>e.then===void 0?[]:[`node:${e.then}.kind`,`node:${e.then}.outcome`,`node:${e.then}`]))],b=S(e,[r]);if(a){for(let e of C(b,S(t,[a])))n.push({why:e,at:[`loop:${r.id}.stops`,...l]});let[o,s]=[x(e),x(t)],c=e=>e.kind===`human`||_(e)&&o(e),u=(e,t)=>e.members.some(e=>(t?.members.includes(e)??!1)&&y.has(e)),d=e=>e.kind===`human`?w(e):`${w(e)} that halts the run`,f=e=>JSON.stringify(e),[p,m]=[new Map,new Map];r.stops.forEach((e,t)=>void(p.has(f(e))||p.set(f(e),t))),a.stops.forEach((e,t)=>void m.set(f(e),t));let h=new Map;for(let e of r.stops)m.has(f(e))||(h.get(E(e))??h.set(E(e),[]).get(E(e))).push(e);let v=a.stops.filter(e=>e.kind===`human`&&!p.has(f(e))),O=[...new Set(a.stops.flatMap(e=>e.kind===`human`?[e.every??1]:[]))],k=[`loop:${r.id}.stops`,...l];for(let{at:e,from:t,lead:n,halt:l,before:g,again:_}of A(r.stops,c,a.stops,D(s,u(a,r)))){let r=w(n),a=n.then===void 0?`${r}, which follows the loop's pass edges,`:`${r} that leads on to "${n.then}"`,s=g?l.kind===`human`?_?`between two askings of ${w(l)}, after the person has said go on`:`before ${w(l)} first asks`:`before ${d(l)}`:`on the same pass as ${d(l)}, where it would be the one obeyed`,c=p.get(f(n)),u=h.get(E(n))??[],y=u.find(e=>e.then===n.then&&T(e)!==T(n)),b=n.then===void 0?void 0:u.find(e=>T(e)===T(n)&&e.then!==n.then),x=l.kind===`human`?l.every??1:1,S=c!==void 0&&l.kind===`human`&&!m.has(f(l))&&!O.some(e=>x%e===0)?v.find(e=>e.then===l.then):void 0,C=c===void 0?y?`${a} would go from ${T(y)} to ${T(n)}, and could fire ${s}`:b?`${r} would lead on to "${n.then}"${b.then===void 0?``:`, not to "${b.then}"`}${o(b)?`, where it halted the run`:``}${b===l?``:`, and could fire ${s}`}`:`${a} would come into the loop, and could fire ${s}`:S?`a person would be asked every ${S.every??1} rounds where it was every ${x}: on pass ${x} nobody would be asked, and ${a} could fire on a pass where a person was asked`:!g&&c>t&&(m.get(f(l))??-1)>e?`${a} would be moved ahead of ${d(l)}, and could fire on the same pass`:`${a} could fire ${s}, as it could not before`;i.push({why:C,at:k})}let j=r.stops.find(c);for(let e of j?t.loops:[]){let t=e=>e?.back.some(e=>r.back.includes(e)||a.back.includes(e))??!1;if(e.id===r.id||!t(e))continue;let n=g.get(e.id),o=new Set(t(n)?n.stops.map(f):[]),c=t=>D(s,u(e,t.then===void 0?n??r:n))(t);for(let t of e.stops){if(!c(t)||o.has(f(t)))continue;let a=`${w(t)} among its stops, which ${t.then===void 0?`follows that loop's pass edges`:`leads on to "${t.then}"`},`;i.push({why:`the loop "${e.id}" would count rounds that "${r.id}" counts, and ${a} could fire before ${d(j)}`,at:n?[`loop:${e.id}.stops`,`loop:${e.id}.back`]:[`loop:${e.id}`]})}}r.bar&&a.bar?.acceptance!==r.bar.acceptance&&n.push({why:a.bar?`changes the bar's acceptance`:`removes the loop's bar`,at:[`loop:${r.id}.bar`]})}for(let e of r.back){let i=v.get(e);if(!i)continue;let o=f.has(e)?[f.get(e)]:t.edges.filter(e=>e.from===i.from&&e.to===i.to);for(let e of o){if(a?.back.includes(e.id))continue;let i=t.loops.filter(t=>t.back.includes(e.id));n.push({why:i.length===0?`the rounds that "${e.id}" starts would no longer be counted by any loop`:`the rounds that "${e.id}" starts would be counted by ${h(i.map(e=>e.id))}, not against the stops of "${r.id}"`,at:[`loop:${r.id}.back`,`loop:${r.id}`,...i.flatMap(e=>[`loop:${e.id}`,`loop:${e.id}.back`])]})}}let O=new Set(r.members);for(let i of t.loops){if(i.id===r.id)continue;let t=new Set(e.loops.find(e=>e.id===i.id)?.back??[]);for(let e of i.back){let o=f.get(e),s=v.get(e);!o||t.has(e)&&s?.from===o.from&&s.to===o.to||a?.back.includes(e)||!O.has(o.from)||!O.has(o.to)||n.push({why:`a round between "${o.from}" and "${o.to}", which the loop "${r.id}" bounds, would be counted by "${i.id}" and not against its stops`,at:[`loop:${i.id}`,`loop:${i.id}.back`,`edge:${e}`,`edge:${e}.from`,`edge:${e}.to`]})}}let k=a?r.members.filter(e=>o.has(e)&&!a.members.includes(e)):[];a&&r.members.length>0&&!r.members.some(e=>a.members.includes(e))?n.push({why:`the loop "${r.id}" would keep its stops and bound none of the nodes it did`,at:[`loop:${r.id}.members`,`loop:${r.id}.back`]}):k.length>0&&n.push({why:`the loop "${r.id}" would no longer bound ${h(k)}, which ${k.length===1?`is`:`are`} still in the graph`,at:[`loop:${r.id}.members`]});let N=a?r.members.filter(e=>!o.has(e)):[],P=N.length>0?t.nodes.filter(e=>!s.has(e.id)&&!a.members.includes(e.id)&&e.kind!==`stop`&&d.has(e.id)).map(e=>e.id):[];if(P.length>0&&n.push({why:`removes ${h(N)}, which the loop "${r.id}" bounded, while ${h(P)} would come in on a round it does not count: it may be the same step under another name`,at:[...N.map(e=>`node:${e}`),`loop:${r.id}.members`]}),a&&a.stops.some(e=>e.kind===`budget`&&e.measure===`dispatches`)){let e=new Set(t.loops.filter(e=>e.id!==r.id).flatMap(e=>e.back)),i=u.filter(t=>t.edge!==void 0&&!e.has(t.edge)),o=e=>t=>i.filter(n=>e(n)[0]===t).map(t=>e(t)[1]),c=(e,t)=>{let n=new Set(e),r=[...n];for(let e=r.pop();e!==void 0;e=r.pop())for(let i of t(e))n.has(i)||r.push((n.add(i),i));return n},l=c(a.members,o(e=>[e.from,e.to])),d=c(a.members,o(e=>[e.to,e.from])),f=t.nodes.filter(e=>!s.has(e.id)&&(e.kind===`agent`||e.kind===`check`)&&!a.members.includes(e.id)&&l.has(e.id)&&d.has(e.id)).map(e=>e.id);f.length>0&&n.push({why:`${h(f)} would work on the rounds of the loop "${r.id}" and not be among its members: its budget of dispatches would not count ${f.length===1?`it`:`them`}`,at:[...f.map(e=>`node:${e}`),`loop:${r.id}.members`]})}if(a){let i=new Set(c.filter(e=>e.person).map(j)),s=M(e,r,i),l=[...new Set([...r.members.filter(e=>o.has(e)),...a.members])],u=0,d=M(t,{id:r.id,members:l,back:a.back},i),g=r.members.some(e=>[...d.closers.get(e)??[]].some(t=>!s.closers.get(e)?.has(t))),_=e=>e.edge!==void 0&&v.has(e.edge)&&(v.get(e.edge).from!==e.from||v.get(e.edge).to!==e.to),y=g?[...d.ways].filter(([e,t])=>!s.ways.has(e)||_(t)):[];for(let[,i]of y){let a=i.edge===void 0?void 0:v.get(i.edge),o=i.edge===void 0?[]:t.loops.filter(e=>e.back.includes(i.edge)),s=i.edge===void 0?e.loops.find(e=>e.id===i.loop)?.stops:void 0,c=i.edge===void 0?p(s,m.get(i.loop)?.stops)?[]:[`loop:${i.loop}.stops`,`loop:${i.loop}`]:a===void 0?[`edge:${i.edge}`]:[`from`,`to`,`when`].filter(e=>!p(a[e],f.get(i.edge)[e])).map(e=>`edge:${i.edge}.${e}`);c.length!==0&&(u+=1,n.push({why:i.edge===void 0?`a stop of the loop "${i.loop}" would lead back to "${i.to}": a way round the nodes of "${r.id}" that its stops do not count`:`"${i.edge}" (${i.from} → ${i.to}) would make a way round the nodes of "${r.id}" that its stops do not count${o.length>0?`: ${h(o.map(e=>e.id))} would count it, and each time round "${r.id}" starts afresh`:``}`,at:[...c,...o.flatMap(e=>[`loop:${e.id}`,`loop:${e.id}.back`])]}))}g&&u===0&&n.push({why:`there would be a way round the nodes of "${r.id}" that its stops do not count`,at:[`loop:${r.id}.members`,`loop:${r.id}.back`]})}}return{losses:n,fired:i}}function P(e,t){let a=[],o=new Map(t.nodes.map(e=>[e.id,e])),s=new Map(t.edges.map(e=>[e.id,e])),c=new Map(e.edges.map(e=>[e.id,e])),l=new Map(e.nodes.map(e=>[e.id,e]));for(let i of e.nodes){let c=o.get(i.id);if(i.kind===`human-gate`){if(!c)a.push({why:`removes a human gate`,at:[`node:${i.id}`]});else if(c.kind!==`human-gate`)a.push({why:`a human gate becomes another kind of node`,at:[`node:${i.id}.kind`]});else{let e=(i.options??[]).filter(e=>!(c.options??[]).includes(e));e.length>0&&a.push({why:`the gate would no longer offer ${h(e)}`,at:[`node:${i.id}.options`],gain:!0})}}if(g(i).length>0){let e=g(i).filter(e=>!g(c).includes(e));c?e.length>0&&a.push({why:`removes the irreversible marker ${h(e)}`,at:[`node:${i.id}.irreversible`,`node:${i.id}.kind`]}):a.push({why:`removes a node marked irreversible (${g(i).join(`, `)}): what takes its place carries no such mark unless it is given one`,at:[`node:${i.id}`],gain:!0})}if(i.kind===`stop`&&i.outcome===`halt`&&c?.kind===`stop`&&F(c)&&a.push({why:`the stop "${i.id}" would end in success where it halted: what led there to stop the run would now end it well`,at:[`node:${i.id}.outcome`]}),i.kind===`check`){let e=t.nodes.filter(e=>e.kind===`check`&&l.get(e.id)?.kind!==`check`),n=e.map(e=>`"${e.id}": ${e.check.run===void 0?`of kind "${e.check.kind}"`:`runs ${JSON.stringify(e.check.run)}`}, passes on ${JSON.stringify(e.check.pass)}${e.check.threshold===void 0?``:`, threshold ${e.check.threshold}`}`).join(`, and `),r=`while ${e.length===1?`a check`:`checks`} the graph has not ${e.length===1?`comes`:`come`} in (${n}): if that is this check under another id, allowing this`;if(!c&&e.length>0)a.push({why:`removes a check, ${r} name allows every change made to it and every way round it`,at:[`node:${i.id}`],swap:`removes a check`});else if(!c)a.push({why:`removes a check`,at:[`node:${i.id}`]});else if(c.kind!==`check`&&e.length>0)a.push({why:`a check becomes another kind of node, ${r} change allows every change made to it and every way round it`,at:[`node:${i.id}.kind`,`node:${i.id}.check`],swap:`a check becomes another kind of node`});else if(c.kind!==`check`)a.push({why:`a check becomes another kind of node`,at:[`node:${i.id}.kind`,`node:${i.id}.check`]});else{let[e,t]=[i.check,c.check],n=[...new Set([...Object.keys(e),...Object.keys(t)])].filter(n=>!p(e[n],t[n]));n.length>0&&a.push({why:`changes the check's definition (${n.join(`, `)}): what it runs and what counts as a pass may be tightened and not loosened, and a program cannot tell which this is`,at:[`node:${i.id}.check`]})}}if(r(i)){c?r(c)||a.push({why:c.kind===`agent`?`a critic is given another role`:`a critic becomes another kind of node`,at:[`node:${i.id}.role`,`node:${i.id}.kind`]}):a.push({why:`removes a critic`,at:[`node:${i.id}`]});let u=e=>e.edges.filter(e=>e.to===i.id),d=new Set(e.edges.map(e=>e.id));for(let n of c?u(e):[]){let e=s.get(n.id),r=new Set(t.edges.filter(e=>e.from===n.from&&!l.has(e.to)).map(e=>e.to)),c=e&&e.from===n.from&&e.to===i.id?[e]:u(t).filter(e=>!d.has(e.id)&&(!o.has(n.from)||e.from===n.from||r.has(e.from))),f=new Set(c.flatMap(e=>e.evidence??[])),p=(n.evidence??[]).filter(e=>!f.has(e));p.length>0&&a.push({why:`the critic would no longer be handed ${h(p)} by "${n.from}"`,at:[`edge:${n.id}.evidence`,`edge:${n.id}.to`,`edge:${n.id}.from`,`edge:${n.id}`,`node:${n.from}`]})}for(let r of u(t)){let t=e.edges.find(e=>e.id===r.id);n(r)===`shared`&&!(t&&t.to===i.id&&n(t)===`shared`)&&a.push({why:`the critic would share its builder's context`,at:[`edge:${r.id}.isolation`,`edge:${r.id}.to`,`edge:${r.id}`]})}}}for(let n of e.edges){let e=s.get(n.id);if(n.approval===!0){e?e.approval!==!0&&a.push({why:`removes a person's approval from the edge`,at:[`edge:${n.id}.approval`]}):a.push({why:`removes an edge that needs a person's approval`,at:[`edge:${n.id}`,`node:${n.from}`,`node:${n.to}`]});for(let r of e?t.edges:[]){if(r.id===n.id||r.from!==e.from||r.to!==e.to||r.approval===!0)continue;let t=c.get(r.id),i=t===void 0?[`edge:${r.id}`]:[`from`,`to`,`approval`].filter(e=>!p(t[e],r[e])).map(e=>`edge:${r.id}.${e}`);i.length>0&&a.push({why:`"${r.id}" would lead from "${r.from}" to "${r.to}" beside "${n.id}", which needs a person's approval, and need none`,at:i})}}let u=l.get(n.from);u?.kind===`human-gate`&&o.get(n.from)?.kind===`human-gate`&&!t.edges.some(e=>e.from===n.from&&i(e)===i(n))&&a.push({why:`"${i(n)}" at the human gate "${n.from}" would lead nowhere`,at:[`edge:${n.id}`,`edge:${n.id}.from`,`edge:${n.id}.when`,`node:${n.to}`],gain:!0}),e&&i(e)!==i(n)&&(n.approval===!0||u?.kind===`human-gate`?a.push({why:`changes what a person's answer leads to`,at:[`edge:${n.id}.when`]}):u&&r(u)&&a.push({why:`changes what the critic's verdict leads to`,at:[`edge:${n.id}.when`]}))}let u=new Map((t.policies??[]).map(e=>[e.id,e]));for(let t of e.policies??[]){let e=t.kind===`critic-isolation`?`removes critic isolation`:t.kind===`no-self-grading`?`lets a node grade its own work`:t.kind===`no-live-graph-rewrite`?`lets a run rewrite the graph where it could only propose`:void 0,n=u.get(t.id),r=n?[`kind`,`scope`,`params`].filter(e=>!p(n[e],t[e])):[];e===void 0||n&&r.length===0||a.push({why:e,at:n?r.map(e=>`policy:${t.id}.${e}`):[`policy:${t.id}`]})}return a}var F=e=>e.kind===`stop`&&(e.outcome??`success`)===`success`;function I(e,t,n){let r=new Map;for(let e of t)s(e,n)||(r.get(e.to)??r.set(e.to,[]).get(e.to)).push(e.from);let i=new Set(e.nodes.filter(F).map(e=>e.id)),a=[...i];for(let e=a.pop();e!==void 0;e=a.pop())for(let t of r.get(e)??[])i.has(t)||(i.add(t),a.push(t));return i}function L(e,t){let n=[],r=new Set(e.nodes.map(e=>e.id)),o=new Set(t.nodes.map(e=>e.id)),m=u(t,`every`);for(let e of t.nodes)!r.has(e.id)&&g(e).length>0&&m.has(e.id)&&n.push({why:`adds an irreversible step that a run reaches without a person`,at:[`node:${e.id}`]});let _=new Map(e.edges.map(e=>[e.id,e])),v=new Map(t.edges.map(e=>[e.id,e])),y=new Map(e.loops.map(e=>[e.id,e])),b=new Map(t.loops.map(e=>[e.id,e])),x=new Set(c(t)),S=new Set(e.loops.flatMap(e=>e.back)),C=a(t),w=a(e),T=new Set,E=new Set,D=new Map,O=t=>D.get(t)??D.set(t,l(e,[t])).get(t),k=[],A=(e,t,r)=>{let i=`${e!==`every`&&`critic`in e?e.critic:``}\n${t}\n${r.at.join(` `)}`;E.has(i)||(E.add(i),n.push(r))};for(let a of d(e,t)){let c=u(e,a),d=u(t,a),m=`that does not pass ${f(a)}`,g=`${a!==`every`&&`critic`in a?a.critic:``}\n`,D=e.nodes.filter(e=>!o.has(e.id)&&!c.has(e.id)&&!T.has(g+e.id)),j=t.nodes.filter(e=>!r.has(e.id)&&d.has(e.id));if(j.length>0)for(let e of D)T.add(g+e.id),n.push({why:`removes "${e.id}", which a run reached only by passing ${f(a)}, while ${h(j.map(e=>e.id))} would come in with no such need: it may be the same step under another name`,at:[`node:${e.id}`]});let M=0,N=e=>{if(e.edge!==void 0){let t=_.get(e.edge);if(!t)return[`edge:${e.edge}`];let n=[`from`,`to`,`approval`,`when`].filter(n=>!p(t[n],v.get(e.edge)[n]));return n.length>0?n.map(t=>`edge:${e.edge}.${t}`):w.some(t=>t.edge===e.edge&&s(t,a))?[`node:${e.from}.kind`,`node:${e.from}.role`]:void 0}let t=y.get(e.loop);if(!t)return[`loop:${e.loop}`];let n=[`stops`,`members`].filter(n=>!p(t[n],b.get(e.loop)[n]));return n.length>0?n.map(t=>`loop:${e.loop}.${t}`):void 0},P=(e,t)=>{M+=1,A(a,e,t)},L=new Set(t.nodes.filter(e=>r.has(e.id)&&!c.has(e.id)&&d.has(e.id)).map(e=>e.id));for(let e of L.size>0?C:[]){if(s(e,a)||!d.has(e.from)||!L.has(e.to))continue;let t=N(e);t&&(e.edge===void 0?P(e.to,{why:`a stop of the loop would lead on to "${e.to}", a way ${m}`,at:t}):P(e.to,{why:`${_.has(e.edge)?`opens`:`adds`} a way into "${e.to}" ${m}`,at:t}))}let R=a===`every`||!(`when`in a)||a.when===void 0,z=a===`every`?void 0:`gate`in a?a.gate:`critic`in a?a.critic:void 0;for(let n of R?t.nodes:[]){if(!r.has(n.id)||n.id===z)continue;let i=l(e,[n.id],a),o=l(t,[n.id],a),c=new Set([...o].filter(e=>r.has(e)&&!i.has(e)&&O(n.id).has(e)));for(let e of c.size>0?C:[]){if(e.from===e.to||s(e,a)||!o.has(e.from)||!c.has(e.to))continue;let t=N(e);if(!t)continue;let n=e.edge===void 0?`a stop of the loop would lead on from "${e.from}" to "${e.to}", a way ${m}`:`${_.has(e.edge)?`opens`:`adds`} a way from "${e.from}" to "${e.to}" ${m}`;k.push([a,e.to,{why:n,at:t}])}}for(let n of L){if(!x.has(n))continue;let r=`nothing would lead to "${n}", so a run would start there, where every way to it passed ${f(a)}`;for(let i of e.edges){if(i.to!==n||S.has(i.id))continue;let e=v.get(i.id);e&&e.to!==n?P(`start ${n}`,{why:r,at:[`edge:${i.id}.to`]}):e?P(`start ${n}`,{why:r,at:t.loops.filter(e=>e.back.includes(i.id)).flatMap(e=>[`loop:${e.id}.back`,`loop:${e.id}`])}):P(`start ${n}`,{why:r,at:[o.has(i.from)?`edge:${i.id}`:`node:${i.from}`]})}}let B=typeof a==`object`&&`critic`in a&&a.when!==void 0?new Set(e.edges.filter(e=>e.from===a.critic).map(i)):new Set,V=B.size>1&&!B.has(`pass`),H=R||V||typeof a==`object`&&`critic`in a&&a.when===`pass`,U=H?I(e,w,a):new Set,W=H?I(t,C,a):new Set,G=new Set(t.nodes.filter(e=>e.kind!==`stop`&&r.has(e.id)&&!U.has(e.id)&&W.has(e.id)).map(e=>e.id));for(let e of G.size>0?C:[]){if(s(e,a)||!G.has(e.from)||!W.has(e.to))continue;let t=N(e),n=`${a!==`every`&&`critic`in a?a.critic:``}\n`;t&&![...E].some(e=>e.startsWith(n)&&e.endsWith(`\n${t.join(` `)}`))?P(`ends ${e.to}`,{why:`adds a way from "${e.from}" to end in success ${m}`,at:t}):t&&(M+=1)}let K=new Set(e.nodes.filter(F).map(e=>e.id));for(let e of G.size>0?t.nodes:[])F(e)&&r.has(e.id)&&!K.has(e.id)&&W.has(e.id)&&P(`ends ${e.id}`,{why:`a run could end in success at "${e.id}", a way ${m}`,at:[`node:${e.id}.outcome`,`node:${e.id}.kind`]});M===0&&(L.size>0||G.size>0)&&n.push({why:L.size>0?`a run would reach ${h([...L])} by a way ${m}`:`a run could end in success from ${h([...G])} by a way ${m}`,at:[]})}return{losses:n,later:k.map(([,,e])=>e)}}function R(e,t){let n=[],r=new Set(a(e).filter(e=>e.person).map(j)),i=new Set(a(t).filter(e=>e.person).map(j)),o=new Set(t.nodes.map(e=>e.id)),s=new Set(t.nodes.filter(e=>e.kind===`human-gate`).map(e=>e.id));for(let a of e.loops){let c=t.loops.find(e=>e.id===a.id);if(!c||!(a.stops.some(_)||a.bar!==void 0))continue;let l={id:a.id,members:[...new Set([...a.members.filter(e=>o.has(e)),...c.members])],back:c.back},u=M(e,a,r),d=[...M(t,l,i).ways].filter(([e,t])=>t.person&&!r.has(e)&&!u.ways.has(e));if(d.length===0)continue;let f=[...new Set(d.map(([,e])=>e.edge===void 0?`the stop where a person is asked, which continues at "${e.to}"`:s.has(e.from)?`"${e.when}" at the human gate "${e.from}" (${e.edge})`:`the approval asked on "${e.edge}"`))],p=[...S(t,[c])].filter(([e])=>e!==`human`).map(([,e])=>`${e.name} (${b(e.halt??e.any,e.unit)})`);n.push(`the loop "${a.id}": ${p.length>0?p.join(` and `):`its stops`} would count the rounds between two of a person's decisions, and no longer the whole run. A way round its nodes that they do not count is opened each time by ${f.join(`, and by `)}`)}return n}function z(e,t){let n=[],r=`a program cannot tell which way this goes, so it is held either way, and an honest change (a gate put behind the check's pass, more evidence handed to a builder) costs one --allow too, the price of a rule a program can apply`,a=new Set(e.nodes.filter(e=>e.kind===`check`&&t.nodes.some(t=>t.id===e.id&&t.kind===`check`)).map(e=>e.id)),o=new Set(t.nodes.map(e=>e.id)),s=new Map(e.edges.map(e=>[e.id,e])),c=new Map(t.edges.map(e=>[e.id,e]));for(let t of e.edges){if(!a.has(t.from))continue;let e=c.get(t.id);if(!e){n.push({why:`removes "${t.id}", an edge that leaves the check "${t.from}": ${r}`,at:[o.has(t.to)?`edge:${t.id}`:`node:${t.to}`],either:!0});continue}for(let a of new Set([...Object.keys(t),...Object.keys(e)])){let o=a===`when`?i(t)!==i(e):!p(t[a],e[a]);a!==`id`&&o&&n.push({why:`changes "${t.id}", an edge that leaves the check "${t.from}" (${a}): ${r}`,at:[`edge:${t.id}.${a}`],either:!0})}}for(let e of t.edges){if(!a.has(e.from))continue;let t=s.get(e.id);t?t.from!==e.from&&n.push({why:`moves "${e.id}" to leave the check "${e.from}": ${r}`,at:[`edge:${e.id}.from`],either:!0}):n.push({why:`adds "${e.id}", an edge that leaves the check "${e.from}": ${r}`,at:[`edge:${e.id}`],either:!0})}return n}function B(e,t){let n=[],i=new Map(e.nodes.map(e=>[e.id,e])),a=new Map(e.loops.map(e=>[e.id,e])),o=e=>e?.stops.some(e=>e.kind===`bar-passed`)??!1;for(let e of t.loops){let s=a.get(e.id),c=e=>i.get(e),l=e.members.filter(e=>c(e)?.kind===`check`&&t.nodes.some(t=>t.id===e&&t.kind===`check`)),u=s?.members.some(e=>c(e)!==void 0&&r(c(e))&&t.nodes.some(t=>t.id===e&&r(t)))??!1;if(l.length===0||u)continue;let d=s?`the loop "${e.id}", which the check ${h(l)} judges with no critic`:`the new loop "${e.id}", around the check ${h(l)}`;e.bar!==void 0&&s?.bar===void 0&&n.push({why:`gives ${d}, a bar of its own: the lead would stop on the bar's words, a way out that does not pass the check`,at:s?[`loop:${e.id}.bar`]:[`loop:${e.id}`]}),o(e)&&!o(s)&&n.push({why:`adds a stop on "bar passed" to ${d}: a way out that does not pass the check`,at:s?[`loop:${e.id}.stops`]:[`loop:${e.id}`]})}return n}function V(e,t){let n=new Set,i=(e,t)=>e.nodes.some(e=>e.id===t&&r(e)),a=new Map(t.edges.map(e=>[e.id,e]));for(let r of e.edges){let o=a.get(r.id);if(!o)continue;r.approval!==!0&&o.approval===!0&&n.add(`edge:${r.id}.approval`);let[s,c]=[r.evidence??[],o.evidence??[]];o.to===r.to&&i(e,r.to)&&i(t,r.to)&&s.every(e=>c.includes(e))&&n.add(`edge:${r.id}.evidence`)}return n}function H(e,t){let n=new Set,r=new Set(e.nodes.filter(e=>e.kind===`stop`&&e.outcome===`halt`).map(e=>e.id)),i=e=>e.kind===`bar-passed`||e.then!==void 0&&!r.has(e.then);for(let r of e.loops){let e=t.loops.find(e=>e.id===r.id);if(!e)continue;let a=new Map;e.stops.forEach((e,t)=>void(a.get(JSON.stringify(e))??a.set(JSON.stringify(e),[]).get(JSON.stringify(e))).push(t));let o=new Set(a.keys()),s=r.stops.map(e=>a.get(JSON.stringify(e))?.shift()),c=1/0,l=!1;for(let e=r.stops.length-1;e>=0;--e){let t=s[e];l||=i(r.stops[e])&&(t===void 0?!o.has(JSON.stringify(r.stops[e])):t>c),t!==void 0&&(c=Math.min(c,t))}l&&n.add(`loop:${r.id}.stops`)}return n}function U(e,t){let n=H(e,t);return n.size===0?W(e,t):W(e,t).map(e=>e.at.some(e=>n.has(e))?{...e,gain:!0}:e)}function W(e,t){let n=[...G(e,t),...B(e,t)],r=z(e,t);if(r.length===0)return n;let i=new Set(n.flatMap(e=>e.at)),a=V(e,t);return[...n,...r.filter(e=>!(a.has(e.at[0])&&!i.has(e.at[0])))]}function G(e,t){let n=new Set,r=L(e,t),i=N(e,t),a=P(e,t),o=[...a,...i.losses,...r.losses],s=new Set(o.flatMap(e=>e.at)),c=new Set,l=r.later.filter(e=>!e.at.some(e=>s.has(e))&&!c.has(e.at.join(` `))&&c.add(e.at.join(` `)));return[...a,...i.losses,...i.fired,...r.losses,...l].filter(e=>{let t=`${e.why}\n${e.at.join(` `)}`;return!n.has(t)&&(n.add(t),!0)})}var K=e=>JSON.stringify(e),q=[`fixed`,`propose`,`adaptive`],J=new Set([`grooph`,`id`,`name`,`version`,`lineage`,`notes`,`layout`,`nodes`,`edges`,`loops`,`policies`,`groups`]);function Y(e,t){let n=[],r=[[`node`,e.nodes,t.nodes],[`edge`,e.edges,t.edges],[`loop`,e.loops,t.loops],[`policy`,e.policies??[],t.policies??[]],[`group`,e.groups??[],t.groups??[]]];for(let[e,t,i]of r){let r=new Map(i.map(e=>[e.id,e])),a=new Set(t.map(e=>e.id));for(let i of t){let t=r.get(i.id);if(!t){n.push({name:`${e}:${i.id}`,kind:`remove`});continue}for(let r of new Set([...Object.keys(i),...Object.keys(t)]))r!==`id`&&K(i[r])!==K(t[r])&&n.push({name:`${e}:${i.id}.${r}`,kind:`change`})}for(let t of i)a.has(t.id)||n.push({name:`${e}:${t.id}`,kind:`add`})}let i=e,a=t;for(let e of new Set([...Object.keys(i),...Object.keys(a)]))!J.has(e)&&K(i[e])!==K(a[e])&&n.push({name:`graph:${e}`,kind:`change`});return n}function ee(e,n){let[r,i]=[t(e),t(n)];return q.indexOf(i)<=q.indexOf(r)?[]:[{why:`the adaptation level would go from "${r}" to "${i}": the lead may change more of the graph during a run`,at:K(e.adaptation)===K(n.adaptation)?[]:[`graph:adaptation`]}]}var X=(e,t)=>[...U(e,t),...ee(e,t)];function Z(e,t,n={}){let r=Y(e,t),i=new Set(r.map(e=>e.name)),a=(e,t,n)=>{for(let a of e){if(t!==`loosens`&&a.either)continue;let e=new Set(a.at.filter(e=>i.has(e)));(e.size!==0||n)&&(r=r.map(n=>e.size>0&&!e.has(n.name)||m(n[t],a.why)||t!==`loosens`&&(m(n.loosens,a.why)||n.kind===`add`&&n.name.startsWith(`loop:`))?n:{...n,[t]:n[t]===void 0?a.why:`${n[t]}; ${a.why}`}))}},o=X(e,t);a(o,`loosens`,!0);let s=X(t,e),c=o.some(e=>e.swap);c?a(s.map(e=>e.swap?{...e,why:e.swap}:e),`unjudged`,!1):(a(s.filter(e=>!e.gain),`tightens`,!1),a(s.filter(e=>e.gain),`unjudged`,!1)),r.sort((e,t)=>Number(t.loosens!==void 0)-Number(e.loosens!==void 0));let l=new Set(n.allow??[]);return{changes:r,refused:r.filter(e=>e.loosens!==void 0&&!l.has(e.name)),unknown:[...l].filter(e=>!i.has(e)),notices:R(e,t),swapped:c}}function te(e,t,n){let r=e=>/^[A-Za-z0-9_.:/@=+-]+$/.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`;return[`grooph`,`adopt`,r(e),...n===void 0?[]:[`--into`,r(n)],`--write`,...t.flatMap(e=>[`--allow`,r(e)])].join(` `)}var Q=e(),ne=e=>()=>void navigator.clipboard?.writeText(e).catch(()=>void 0),$=e=>e?.scrollIntoView({block:`start`});function re(e,t,n){if(!n)return(0,Q.jsx)(`p`,{className:`field-hint`,"data-brakes":`not-compared`,ref:$,children:`Its brakes were not compared with the graph's: the copy is not a valid graph. Open the copy to see why before you use it.`});let r=Z(e,t);if(r.refused.length+r.notices.length===0)return null;let i=r.notices.map(e=>(0,Q.jsxs)(`p`,{"data-brakes":`note`,children:[`Note: `,e]},e));return r.refused.length===0?(0,Q.jsx)(`div`,{className:`field-hint`,"data-brakes":`said`,ref:$,children:i}):(0,Q.jsxs)(`div`,{className:`refusal-hint`,"data-brakes":`proposed`,ref:$,children:[(0,Q.jsxs)(`p`,{children:[(0,Q.jsx)(`strong`,{children:`This copy loosens a brake the graph has.`}),` It is the run's working copy with this proposal applied; either may have done it, and it is yours to allow or not: read each line before you use the copy.`]}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`loosens`,children:r.refused.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` `,e.loosens]},e.name))}),i]})}function ie(e,t,n){let r=Z(e,t),i=r.changes.filter(e=>e.tightens!==void 0&&e.loosens===void 0),a=r.changes.filter(e=>e.unjudged!==void 0&&e.loosens===void 0),o=te(`.grooph/${e.id}/runs/${n}`,r.refused.map(e=>e.name)),s=(0,Q.jsxs)(Q.Fragment,{children:[i.length>0?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{children:r.refused.length>0?`It also tightens a brake:`:`It tightens a brake:`}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`tightens`,children:i.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` undoing it: `,e.tightens]},e.name))})]}):null,a.length>0?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{children:r.swapped?`With a check removed in this copy, no change is called a tightening. If the check that comes in is the same one under another id, these may be built around it:`:`An answer a gate did not give, a step marked irreversible that the graph did not have, or a stop of a loop that leads on, where it is new, changed or put ahead, lets a person or a run do what it could not before. A change that brings one is named here and not called a tightening, whatever else it does:`}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`unjudged`,children:a.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` undoing it: `,e.unjudged]},e.name))})]}):null,r.notices.map(e=>(0,Q.jsxs)(`p`,{"data-brakes":`note`,children:[`Note: `,e]},e))]});return r.refused.length===0?{ok:!0,view:i.length+a.length+r.notices.length>0?(0,Q.jsx)(`div`,{className:`field-hint`,"data-brakes":`said`,children:s}):null}:{ok:!1,view:(0,Q.jsxs)(`div`,{className:`refusal`,role:`alert`,"data-brakes":`refused`,children:[(0,Q.jsxs)(`p`,{children:[(0,Q.jsx)(`strong`,{children:`Not adopted: this working copy loosens a brake.`}),` A run may tighten a brake and never loosen one. Nothing was saved.`]}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`loosens`,children:r.refused.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` `,e.loosens]},e.name))}),(0,Q.jsx)(`p`,{children:`To adopt it on purpose, run this in the project's folder. It names each change above:`}),(0,Q.jsx)(`pre`,{className:`issue-lines`,"data-brakes":`command`,children:o}),(0,Q.jsx)(`button`,{type:`button`,className:`btn`,onClick:ne(o),children:`Copy the command`}),s]})}}export{ie as judge,re as loosened};
1
+ import{t as e}from"./index-B5ZkSF4L.js";import{Jt as t,Zt as n,en as r}from"./share-DV3wsAsJ.js";var i=e=>typeof e.when==`object`?e.when.verdict:e.when??`always`;function a(e){let t=new Map(e.nodes.map(e=>[e.id,e.kind])),n=new Set(e.nodes.filter(e=>e.kind===`stop`&&e.outcome===`halt`).map(e=>e.id)),a=new Set(e.nodes.filter(r).map(e=>e.id)),o=e.edges.map(e=>({from:e.from,to:e.to,person:e.approval===!0||t.get(e.from)===`human-gate`,edge:e.id,when:i(e)}));for(let t of e.loops)for(let e of t.stops){if(e.then===void 0)continue;let r=e.kind===`max-iterations`||e.kind===`budget`||e.kind===`human`,i=r&&n.has(e.then),s=e.kind===`bar-passed`?t.members.filter(e=>a.has(e)):[];for(let n of t.members)o.push({from:n,to:e.then,person:e.kind===`human`,loop:t.id,...r?{fires:r}:{},...i?{escalates:i}:{},...s.length>0?{verdictOf:s}:{}})}return o}var o=e=>`${e.loop}\n${e.to}`;function s(e,t){if(t===`every`)return e.person;if(`approval`in t)return e.edge===t.approval;if(`critic`in t&&(e.escalates||e.fires&&t.stops?.has(o(e)))||`critic`in t&&e.verdictOf?.includes(t.critic)&&(t.when===void 0||t.when===`pass`))return!0;let n=`gate`in t?t.gate:t.critic;return e.edge!==void 0&&e.from===n&&(t.when===void 0||e.when===t.when)}function c(e){let t=new Set(e.loops.flatMap(e=>e.back));return e.nodes.filter(n=>!e.edges.some(e=>e.to===n.id&&!t.has(e.id))).map(e=>e.id)}function l(e,t,n){let r=new Set(e.nodes.map(e=>e.id)),i=new Map;for(let t of a(e))n!==void 0&&s(t,n)||!r.has(t.from)||!r.has(t.to)||(i.get(t.from)??i.set(t.from,[]).get(t.from)).push(t.to);let o=new Set(t),c=[...o];for(let e=c.pop();e!==void 0;e=c.pop())for(let t of i.get(e)??[])o.has(t)||(o.add(t),c.push(t));return o}var u=(e,t)=>l(e,c(e),t);function d(e,t){let n=new Map(t.nodes.map(e=>[e.id,e])),s=new Set(t.edges.filter(e=>e.approval===!0).map(e=>e.id)),c=t=>[...new Set(e.edges.filter(e=>e.from===t).map(i))],l=[`every`],u=new Set(a(e).filter(e=>e.fires).map(o));for(let t of e.nodes)t.kind===`human-gate`&&n.get(t.id)?.kind===`human-gate`&&l.push({gate:t.id},...c(t.id).map(e=>({gate:t.id,when:e})));for(let t of e.edges)t.approval===!0&&s.has(t.id)&&l.push({approval:t.id});for(let t of e.nodes){let e=n.get(t.id);if(r(t)&&e&&r(e)&&l.push({critic:t.id},...c(t.id).map(e=>({critic:t.id,when:e}))),t.kind===`check`&&e?.kind===`check`)for(let e of[{check:!0},{check:!0,stops:u}])l.push({critic:t.id,...e},...c(t.id).map(n=>({critic:t.id,when:n,...e})))}return l}function f(e){if(e===`every`)return`a person`;if(`approval`in e)return`the approval on "${e.approval}"`;if(`gate`in e)return e.when===void 0?`the human gate "${e.gate}"`:`"${e.when}" at the human gate "${e.gate}"`;let t=e.check?`check`:`critic`;return e.when===void 0?`the ${t} "${e.critic}"`:`"${e.when}" from the ${t} "${e.critic}"`}var p=(e,t)=>JSON.stringify(e)===JSON.stringify(t),m=(e,t)=>e!==void 0&&(e===t||e.startsWith(`${t}; `)||e.endsWith(`; ${t}`)||e.includes(`; ${t}; `)),h=e=>e.map(e=>`"${e}"`).join(`, `),g=e=>e?.kind===`agent`?e.irreversible??[]:[],_=e=>e.kind===`max-iterations`||e.kind===`budget`||e.kind===`human`,v={dispatches:`dispatch`,minutes:`minute`,turns:`turn`,tokens:`token`,rounds:`round`},y=(e,t)=>`${e} ${e===1?v[t]??t:t}`,b=(e,t)=>t===``?`${e}`:y(e,t);function x(e){let t=new Map(e.nodes.map(e=>[e.id,e]));return e=>{if(e.then===void 0)return!0;let n=t.get(e.then);return n?.kind===`human-gate`||n?.kind===`stop`&&n.outcome===`halt`}}function S(e,t){let n=x(e),r=new Map,i=(e,t)=>e===void 0?t:Math.min(e,t);for(let e of t)for(let t of e.stops){let[e,a,o,s]=t.kind===`max-iterations`?[`cap`,`the round cap`,``,t.n]:t.kind===`budget`?[`budget ${t.measure}`,`the budget`,t.measure,t.limit]:t.kind===`human`?[`human`,`the stop where a person is asked`,``,t.every??1]:[void 0,``,``,0];if(e===void 0)continue;let c=r.get(e)??r.set(e,{name:a,unit:o,leads:new Set}).get(e);c.any=i(c.any,s),n(t)?c.halt=i(c.halt,s):(c.lead=i(c.lead,s),c.leads.add(t.then))}return r}function C(e,t){let n=[],r=e=>e.lead!==void 0&&(e.halt===void 0||e.lead<=e.halt);for(let[i,a]of e){let e=t.get(i),o=i===`human`;if(e?.any===void 0)n.push(o?`removes the stop where a person is asked`:`removes ${a.name} (${b(a.any,a.unit)})`);else if(e.any>a.any)n.push(o?`a person would be asked every ${e.any} rounds, not every ${a.any}`:`raises ${a.name} from ${a.any} to ${b(e.any,a.unit)}`);else if(a.halt!==void 0&&e.halt===void 0)n.push(`${a.name} (${b(a.halt,a.unit)}) would no longer halt the run`);else if(a.halt!==void 0&&e.halt>a.halt)n.push(`${a.name} that halts the run would rise from ${a.halt} to ${b(e.halt,a.unit)}`);else if(a.halt!==void 0&&!r(a)&&r(e))n.push(`${o?`a stop that asks a person`:a.name} of ${b(e.lead,a.unit)} that leads on to ${h([...e.leads])} would fire ${e.lead<e.halt?`before`:`as soon as`} the one of ${b(e.halt,a.unit)} that halts the run`);else if(r(e)){let t=[...e.leads].filter(e=>!a.leads.has(e));t.length>0&&n.push(`${a.name} would lead on to ${h(t)}${a.leads.size>0?`, not to ${h([...a.leads])}`:``}`)}}return n}function w(e){switch(e.kind){case`max-iterations`:return`the round cap of ${e.n}`;case`budget`:return`the budget of ${y(e.limit,e.measure)}`;case`human`:return(e.every??1)===1?`the stop where a person is asked`:`the stop where a person is asked every ${y(e.every,`rounds`)}`;case`diminishing-returns`:return`the stop on diminishing returns over ${y(e.rounds,`rounds`)}`;case`evidence-invalid`:return`the stop on evidence invalid for ${y(e.rounds,`rounds`)}`;default:return`the stop on "bar passed"`}}var T=e=>e.kind===`max-iterations`?e.n:e.kind===`budget`?e.limit:e.kind===`human`?e.every??1:e.kind===`bar-passed`?void 0:e.rounds,E=e=>e.kind===`budget`?`budget ${e.measure}`:e.kind===`diminishing-returns`?`${e.kind} ${JSON.stringify([e.metric??null,e.threshold??null])}`:e.kind,D=(e,t)=>n=>n.kind===`human`?!1:n.kind===`bar-passed`?!t&&(n.then===void 0||!e(n)):n.then!==void 0&&!e(n);function O(e){let t=e=>Number.isFinite(e)?Math.max(1,Math.ceil(e)):1;switch(e.kind){case`max-iterations`:return{sort:`cap`,from:t(e.n)};case`human`:return{sort:`person`,every:t(e.every??1)};case`budget`:return{sort:`counted`,key:`budget ${e.measure}`,size:e.limit,from:1,lasting:!0};case`diminishing-returns`:return{sort:`counted`,key:`no progress ${JSON.stringify([e.metric??null,e.threshold??null])}`,size:e.rounds,from:t(e.rounds),lasting:!1};case`evidence-invalid`:return{sort:`counted`,key:`invalid evidence`,size:e.rounds,from:t(e.rounds),lasting:!1};default:return{sort:`counted`,key:`bar passed`,size:0,from:1,lasting:!1}}}function k(e){let t=e.map(O),n=[],r=[],i=new Map,[a,o,s,c]=[!1,1/0,1/0,1/0];t.forEach((e,t)=>{n.push(a),r.push(o),e.sort===`person`?(i.has(e.every)||i.set(e.every,t),a||=e.every===1,s=Math.min(s,e.every)):e.sort===`cap`&&(o=Math.min(o,e.from),s>e.from&&(c=Math.min(c,e.from)))});let l=new Map,u=e=>{let n=l.get(e);if(!n){let r=1/0;n=t.map(t=>{let n=r;return t.sort===`counted`&&t.key===e&&(r=Math.min(r,t.size)),n}),l.set(e,n)}return n},d=new Map;return{timing:t,always:n,capAhead:r,over:c,person:i,divides:e=>{let t=d.get(e);if(t===void 0){t=1/0;for(let[n,r]of i)e%n===0&&(t=Math.min(t,r));d.set(e,t)}return t},least:u}}function A(e,t,n,r){let[i,a]=[k(e),k(n)],o=i.timing.flatMap((e,t)=>e.sort===`cap`?[{from:e.from,at:t}]:[]).sort((e,t)=>e.from-t.from),s=[];return n.forEach((n,c)=>{let l=a.timing[c];if(l.sort===`person`||!r(n)||a.always[c])return;let[u,d]=[l.from,Math.min(a.over,a.capAhead[c]-1)];if(u>d||l.sort===`counted`&&!(a.least(l.key)[c]>l.size))return;let f=[],p=1/0;for(let e of i.timing)f.push(p),e.sort===`person`&&!(a.divides(e.every)<c)&&(p=Math.min(p,e.every));let m=u;if(l.sort===`counted`){let e=i.timing.findIndex(e=>e.sort===`counted`&&e.key===l.key&&e.size<=l.size);e>=0&&(m=Math.max(m,f[e]))}for(let e of o)e.from<=m&&m<f[e.at]&&(m=f[e.at]);let h;for(let[r,o]of e.entries()){let e=i.timing[r];if(!t(o)||i.always[r]||e.sort===`person`&&i.divides(e.every)<r)continue;let[f,p]=[e.sort===`person`?e.every:e.from,Math.min(i.over,i.capAhead[r]-1)];if(f>p||e.sort===`counted`&&!(i.least(e.key)[r]>e.size)||l.sort===`counted`&&l.lasting&&!(i.least(l.key)[r]>l.size))continue;let g=(t,n)=>t<=n&&(e.sort!==`person`||Math.ceil(t/e.every)*e.every<=n),_=g(Math.max(u,f),Math.min(d,p))&&!(e.sort===`person`&&a.divides(e.every)<c)&&!(l.sort===`counted`&&!(i.least(l.key)[r]>l.size))&&!(e.sort===`counted`&&!(a.least(e.key)[c]>e.size));if(Number.isFinite(m)&&m<=d&&g(Math.max(f,m+1),p)){e.sort===`person`&&_?s.push({at:c,from:r,lead:n,halt:o,before:!1}):s.push({at:c,from:r,lead:n,halt:o,before:!0,...e.sort===`person`?{again:m>=e.every}:{}});return}_&&(h??=r)}h!==void 0&&s.push({at:c,from:h,lead:n,halt:e[h],before:!1})}),s}var j=e=>e.edge??`${e.loop} → ${e.to}`;function M(e,t,n){let r=new Set(t.back),i=new Set(e.nodes.filter(e=>e.kind===`human-gate`).map(e=>e.id)),o=a(e).filter(e=>e.from!==e.to&&(e.edge===void 0||!r.has(e.edge))&&(!e.person||n.has(j(e)))),s=n=>n.edge===void 0?[j(n)]:e.loops.filter(e=>e.id!==t.id&&e.back.includes(n.edge)).map(e=>e.id),c=(e,t)=>{let n=new Set(e),r=[...n];for(let e=r.pop();e!==void 0;e=r.pop())for(let i of t(e))n.has(i)||r.push((n.add(i),i));return n},l=o.filter(e=>e.loop===t.id&&t.members.includes(e.to)&&!i.has(e.to)),u=new Map(l.map(e=>[j(e),e])),d=new Map;for(let e of t.members){let t=c([e],e=>o.filter(t=>t.from===e).map(e=>e.to)),n=c([e],e=>o.filter(t=>t.to===e).map(e=>e.from)),r=new Set(l.map(j));for(let e of o)if(t.has(e.from)&&n.has(e.to)){u.set(j(e),e);for(let t of s(e))r.add(t)}d.set(e,r)}return{ways:u,closers:d}}function N(e,t){let n=[],i=[],o=new Set(t.nodes.map(e=>e.id)),s=new Set(e.nodes.map(e=>e.id)),c=a(e),u=a(t),d=new Set(t.nodes.filter(e=>[...l(t,u.filter(t=>t.from===e.id&&t.to!==e.id).map(e=>e.to))].includes(e.id)||u.some(t=>t.edge!==void 0&&t.from===e.id&&t.to===e.id)).map(e=>e.id)),f=new Map(t.edges.map(e=>[e.id,e])),m=new Map(t.loops.map(e=>[e.id,e])),g=new Map(e.loops.map(e=>[e.id,e])),v=new Map(e.edges.map(e=>[e.id,e])),y=new Set(e.nodes.filter(e=>r(e)&&t.nodes.some(t=>t.id===e.id&&r(t))).map(e=>e.id));for(let r of e.loops){if(!(r.stops.some(_)||r.bar!==void 0))continue;let a=m.get(r.id);a||n.push({why:`removes a loop with its stops and its bar`,at:[`loop:${r.id}`]});let l=[...new Set(r.stops.flatMap(e=>e.then===void 0?[]:[`node:${e.then}.kind`,`node:${e.then}.outcome`,`node:${e.then}`]))],b=S(e,[r]);if(a){for(let e of C(b,S(t,[a])))n.push({why:e,at:[`loop:${r.id}.stops`,...l]});let[o,s]=[x(e),x(t)],c=e=>e.kind===`human`||_(e)&&o(e),u=(e,t)=>e.members.some(e=>(t?.members.includes(e)??!1)&&y.has(e)),d=e=>e.kind===`human`?w(e):`${w(e)} that halts the run`,f=e=>JSON.stringify(e),[p,m]=[new Map,new Map];r.stops.forEach((e,t)=>void(p.has(f(e))||p.set(f(e),t))),a.stops.forEach((e,t)=>void m.set(f(e),t));let h=new Map;for(let e of r.stops)m.has(f(e))||(h.get(E(e))??h.set(E(e),[]).get(E(e))).push(e);let v=a.stops.filter(e=>e.kind===`human`&&!p.has(f(e))),O=[...new Set(a.stops.flatMap(e=>e.kind===`human`?[e.every??1]:[]))],k=[`loop:${r.id}.stops`,...l];for(let{at:e,from:t,lead:n,halt:l,before:g,again:_}of A(r.stops,c,a.stops,D(s,u(a,r)))){let r=w(n),a=n.then===void 0?`${r}, which follows the loop's pass edges,`:`${r} that leads on to "${n.then}"`,s=g?l.kind===`human`?_?`between two askings of ${w(l)}, after the person has said go on`:`before ${w(l)} first asks`:`before ${d(l)}`:`on the same pass as ${d(l)}, where it would be the one obeyed`,c=p.get(f(n)),u=h.get(E(n))??[],y=u.find(e=>e.then===n.then&&T(e)!==T(n)),b=n.then===void 0?void 0:u.find(e=>T(e)===T(n)&&e.then!==n.then),x=l.kind===`human`?l.every??1:1,S=c!==void 0&&l.kind===`human`&&!m.has(f(l))&&!O.some(e=>x%e===0)?v.find(e=>e.then===l.then):void 0,C=c===void 0?y?`${a} would go from ${T(y)} to ${T(n)}, and could fire ${s}`:b?`${r} would lead on to "${n.then}"${b.then===void 0?``:`, not to "${b.then}"`}${o(b)?`, where it halted the run`:``}${b===l?``:`, and could fire ${s}`}`:`${a} would come into the loop, and could fire ${s}`:S?`a person would be asked every ${S.every??1} rounds where it was every ${x}: on pass ${x} nobody would be asked, and ${a} could fire on a pass where a person was asked`:!g&&c>t&&(m.get(f(l))??-1)>e?`${a} would be moved ahead of ${d(l)}, and could fire on the same pass`:`${a} could fire ${s}, as it could not before`;i.push({why:C,at:k})}let j=r.stops.find(c);for(let e of j?t.loops:[]){let t=e=>e?.back.some(e=>r.back.includes(e)||a.back.includes(e))??!1;if(e.id===r.id||!t(e))continue;let n=g.get(e.id),o=new Set(t(n)?n.stops.map(f):[]),c=t=>D(s,u(e,t.then===void 0?n??r:n))(t);for(let t of e.stops){if(!c(t)||o.has(f(t)))continue;let a=`${w(t)} among its stops, which ${t.then===void 0?`follows that loop's pass edges`:`leads on to "${t.then}"`},`;i.push({why:`the loop "${e.id}" would count rounds that "${r.id}" counts, and ${a} could fire before ${d(j)}`,at:n?[`loop:${e.id}.stops`,`loop:${e.id}.back`]:[`loop:${e.id}`]})}}r.bar&&a.bar?.acceptance!==r.bar.acceptance&&n.push({why:a.bar?`changes the bar's acceptance`:`removes the loop's bar`,at:[`loop:${r.id}.bar`]})}for(let e of r.back){let i=v.get(e);if(!i)continue;let o=f.has(e)?[f.get(e)]:t.edges.filter(e=>e.from===i.from&&e.to===i.to);for(let e of o){if(a?.back.includes(e.id))continue;let i=t.loops.filter(t=>t.back.includes(e.id));n.push({why:i.length===0?`the rounds that "${e.id}" starts would no longer be counted by any loop`:`the rounds that "${e.id}" starts would be counted by ${h(i.map(e=>e.id))}, not against the stops of "${r.id}"`,at:[`loop:${r.id}.back`,`loop:${r.id}`,...i.flatMap(e=>[`loop:${e.id}`,`loop:${e.id}.back`])]})}}let O=new Set(r.members);for(let i of t.loops){if(i.id===r.id)continue;let t=new Set(e.loops.find(e=>e.id===i.id)?.back??[]);for(let e of i.back){let o=f.get(e),s=v.get(e);!o||t.has(e)&&s?.from===o.from&&s.to===o.to||a?.back.includes(e)||!O.has(o.from)||!O.has(o.to)||n.push({why:`a round between "${o.from}" and "${o.to}", which the loop "${r.id}" bounds, would be counted by "${i.id}" and not against its stops`,at:[`loop:${i.id}`,`loop:${i.id}.back`,`edge:${e}`,`edge:${e}.from`,`edge:${e}.to`]})}}let k=a?r.members.filter(e=>o.has(e)&&!a.members.includes(e)):[];a&&r.members.length>0&&!r.members.some(e=>a.members.includes(e))?n.push({why:`the loop "${r.id}" would keep its stops and bound none of the nodes it did`,at:[`loop:${r.id}.members`,`loop:${r.id}.back`]}):k.length>0&&n.push({why:`the loop "${r.id}" would no longer bound ${h(k)}, which ${k.length===1?`is`:`are`} still in the graph`,at:[`loop:${r.id}.members`]});let N=a?r.members.filter(e=>!o.has(e)):[],P=N.length>0?t.nodes.filter(e=>!s.has(e.id)&&!a.members.includes(e.id)&&e.kind!==`stop`&&d.has(e.id)).map(e=>e.id):[];if(P.length>0&&n.push({why:`removes ${h(N)}, which the loop "${r.id}" bounded, while ${h(P)} would come in on a round it does not count: it may be the same step under another name`,at:[...N.map(e=>`node:${e}`),`loop:${r.id}.members`]}),a&&a.stops.some(e=>e.kind===`budget`&&e.measure===`dispatches`)){let e=new Set(t.loops.filter(e=>e.id!==r.id).flatMap(e=>e.back)),i=u.filter(t=>t.edge!==void 0&&!e.has(t.edge)),o=e=>t=>i.filter(n=>e(n)[0]===t).map(t=>e(t)[1]),c=(e,t)=>{let n=new Set(e),r=[...n];for(let e=r.pop();e!==void 0;e=r.pop())for(let i of t(e))n.has(i)||r.push((n.add(i),i));return n},l=c(a.members,o(e=>[e.from,e.to])),d=c(a.members,o(e=>[e.to,e.from])),f=t.nodes.filter(e=>!s.has(e.id)&&(e.kind===`agent`||e.kind===`check`)&&!a.members.includes(e.id)&&l.has(e.id)&&d.has(e.id)).map(e=>e.id);f.length>0&&n.push({why:`${h(f)} would work on the rounds of the loop "${r.id}" and not be among its members: its budget of dispatches would not count ${f.length===1?`it`:`them`}`,at:[...f.map(e=>`node:${e}`),`loop:${r.id}.members`]})}if(a){let i=new Set(c.filter(e=>e.person).map(j)),s=M(e,r,i),l=[...new Set([...r.members.filter(e=>o.has(e)),...a.members])],u=0,d=M(t,{id:r.id,members:l,back:a.back},i),g=r.members.some(e=>[...d.closers.get(e)??[]].some(t=>!s.closers.get(e)?.has(t))),_=e=>e.edge!==void 0&&v.has(e.edge)&&(v.get(e.edge).from!==e.from||v.get(e.edge).to!==e.to),y=g?[...d.ways].filter(([e,t])=>!s.ways.has(e)||_(t)):[];for(let[,i]of y){let a=i.edge===void 0?void 0:v.get(i.edge),o=i.edge===void 0?[]:t.loops.filter(e=>e.back.includes(i.edge)),s=i.edge===void 0?e.loops.find(e=>e.id===i.loop)?.stops:void 0,c=i.edge===void 0?p(s,m.get(i.loop)?.stops)?[]:[`loop:${i.loop}.stops`,`loop:${i.loop}`]:a===void 0?[`edge:${i.edge}`]:[`from`,`to`,`when`].filter(e=>!p(a[e],f.get(i.edge)[e])).map(e=>`edge:${i.edge}.${e}`);c.length!==0&&(u+=1,n.push({why:i.edge===void 0?`a stop of the loop "${i.loop}" would lead back to "${i.to}": a way round the nodes of "${r.id}" that its stops do not count`:`"${i.edge}" (${i.from} → ${i.to}) would make a way round the nodes of "${r.id}" that its stops do not count${o.length>0?`: ${h(o.map(e=>e.id))} would count it, and each time round "${r.id}" starts afresh`:``}`,at:[...c,...o.flatMap(e=>[`loop:${e.id}`,`loop:${e.id}.back`])]}))}g&&u===0&&n.push({why:`there would be a way round the nodes of "${r.id}" that its stops do not count`,at:[`loop:${r.id}.members`,`loop:${r.id}.back`]})}}return{losses:n,fired:i}}function P(e,n){let a=[],o=new Map(n.nodes.map(e=>[e.id,e])),s=new Map(n.edges.map(e=>[e.id,e])),c=new Map(e.edges.map(e=>[e.id,e])),l=new Map(e.nodes.map(e=>[e.id,e]));for(let i of e.nodes){let c=o.get(i.id);if(i.kind===`human-gate`){if(!c)a.push({why:`removes a human gate`,at:[`node:${i.id}`]});else if(c.kind!==`human-gate`)a.push({why:`a human gate becomes another kind of node`,at:[`node:${i.id}.kind`]});else{let e=(i.options??[]).filter(e=>!(c.options??[]).includes(e));e.length>0&&a.push({why:`the gate would no longer offer ${h(e)}`,at:[`node:${i.id}.options`],gain:!0})}}if(g(i).length>0){let e=g(i).filter(e=>!g(c).includes(e));c?e.length>0&&a.push({why:`removes the irreversible marker ${h(e)}`,at:[`node:${i.id}.irreversible`,`node:${i.id}.kind`]}):a.push({why:`removes a node marked irreversible (${g(i).join(`, `)}): what takes its place carries no such mark unless it is given one`,at:[`node:${i.id}`],gain:!0})}if(i.kind===`stop`&&i.outcome===`halt`&&c?.kind===`stop`&&F(c)&&a.push({why:`the stop "${i.id}" would end in success where it halted: what led there to stop the run would now end it well`,at:[`node:${i.id}.outcome`]}),i.kind===`check`){let e=n.nodes.filter(e=>e.kind===`check`&&l.get(e.id)?.kind!==`check`),t=e.map(e=>`"${e.id}": ${e.check.run===void 0?`of kind "${e.check.kind}"`:`runs ${JSON.stringify(e.check.run)}`}, passes on ${JSON.stringify(e.check.pass)}${e.check.threshold===void 0?``:`, threshold ${e.check.threshold}`}`).join(`, and `),r=`while ${e.length===1?`a check`:`checks`} the graph has not ${e.length===1?`comes`:`come`} in (${t}): if that is this check under another id, allowing this`;if(!c&&e.length>0)a.push({why:`removes a check, ${r} name allows every change made to it and every way round it`,at:[`node:${i.id}`],swap:`removes a check`});else if(!c)a.push({why:`removes a check`,at:[`node:${i.id}`]});else if(c.kind!==`check`&&e.length>0)a.push({why:`a check becomes another kind of node, ${r} change allows every change made to it and every way round it`,at:[`node:${i.id}.kind`,`node:${i.id}.check`],swap:`a check becomes another kind of node`});else if(c.kind!==`check`)a.push({why:`a check becomes another kind of node`,at:[`node:${i.id}.kind`,`node:${i.id}.check`]});else{let[e,t]=[i.check,c.check],n=[...new Set([...Object.keys(e),...Object.keys(t)])].filter(n=>!p(e[n],t[n]));n.length>0&&a.push({why:`changes the check's definition (${n.join(`, `)}): what it runs and what counts as a pass may be tightened and not loosened, and a program cannot tell which this is`,at:[`node:${i.id}.check`]})}}if(r(i)){c?r(c)||a.push({why:c.kind===`agent`?`a critic is given another role`:`a critic becomes another kind of node`,at:[`node:${i.id}.role`,`node:${i.id}.kind`]}):a.push({why:`removes a critic`,at:[`node:${i.id}`]});let u=e=>e.edges.filter(e=>e.to===i.id),d=new Set(e.edges.map(e=>e.id));for(let t of c?u(e):[]){let e=s.get(t.id),r=new Set(n.edges.filter(e=>e.from===t.from&&!l.has(e.to)).map(e=>e.to)),c=e&&e.from===t.from&&e.to===i.id?[e]:u(n).filter(e=>!d.has(e.id)&&(!o.has(t.from)||e.from===t.from||r.has(e.from))),f=new Set(c.flatMap(e=>e.evidence??[])),p=(t.evidence??[]).filter(e=>!f.has(e));p.length>0&&a.push({why:`the critic would no longer be handed ${h(p)} by "${t.from}"`,at:[`edge:${t.id}.evidence`,`edge:${t.id}.to`,`edge:${t.id}.from`,`edge:${t.id}`,`node:${t.from}`]})}for(let r of u(n)){let n=e.edges.find(e=>e.id===r.id);t(r)===`shared`&&!(n&&n.to===i.id&&t(n)===`shared`)&&a.push({why:`the critic would share its builder's context`,at:[`edge:${r.id}.isolation`,`edge:${r.id}.to`,`edge:${r.id}`]})}}}for(let t of e.edges){let e=s.get(t.id);if(t.approval===!0){e?e.approval!==!0&&a.push({why:`removes a person's approval from the edge`,at:[`edge:${t.id}.approval`]}):a.push({why:`removes an edge that needs a person's approval`,at:[`edge:${t.id}`,`node:${t.from}`,`node:${t.to}`]});for(let r of e?n.edges:[]){if(r.id===t.id||r.from!==e.from||r.to!==e.to||r.approval===!0)continue;let n=c.get(r.id),i=n===void 0?[`edge:${r.id}`]:[`from`,`to`,`approval`].filter(e=>!p(n[e],r[e])).map(e=>`edge:${r.id}.${e}`);i.length>0&&a.push({why:`"${r.id}" would lead from "${r.from}" to "${r.to}" beside "${t.id}", which needs a person's approval, and need none`,at:i})}}let u=l.get(t.from);u?.kind===`human-gate`&&o.get(t.from)?.kind===`human-gate`&&!n.edges.some(e=>e.from===t.from&&i(e)===i(t))&&a.push({why:`"${i(t)}" at the human gate "${t.from}" would lead nowhere`,at:[`edge:${t.id}`,`edge:${t.id}.from`,`edge:${t.id}.when`,`node:${t.to}`],gain:!0}),e&&i(e)!==i(t)&&(t.approval===!0||u?.kind===`human-gate`?a.push({why:`changes what a person's answer leads to`,at:[`edge:${t.id}.when`]}):u&&r(u)&&a.push({why:`changes what the critic's verdict leads to`,at:[`edge:${t.id}.when`]}))}let u=new Map((n.policies??[]).map(e=>[e.id,e]));for(let t of e.policies??[]){let e=t.kind===`critic-isolation`?`removes critic isolation`:t.kind===`no-self-grading`?`lets a node grade its own work`:t.kind===`no-live-graph-rewrite`?`lets a run rewrite the graph where it could only propose`:void 0,n=u.get(t.id),r=n?[`kind`,`scope`,`params`].filter(e=>!p(n[e],t[e])):[];e===void 0||n&&r.length===0||a.push({why:e,at:n?r.map(e=>`policy:${t.id}.${e}`):[`policy:${t.id}`]})}return a}var F=e=>e.kind===`stop`&&(e.outcome??`success`)===`success`;function I(e,t,n){let r=new Map;for(let e of t)s(e,n)||(r.get(e.to)??r.set(e.to,[]).get(e.to)).push(e.from);let i=new Set(e.nodes.filter(F).map(e=>e.id)),a=[...i];for(let e=a.pop();e!==void 0;e=a.pop())for(let t of r.get(e)??[])i.has(t)||(i.add(t),a.push(t));return i}function L(e,t){let n=[],r=new Set(e.nodes.map(e=>e.id)),o=new Set(t.nodes.map(e=>e.id)),m=u(t,`every`);for(let e of t.nodes)!r.has(e.id)&&g(e).length>0&&m.has(e.id)&&n.push({why:`adds an irreversible step that a run reaches without a person`,at:[`node:${e.id}`]});let _=new Map(e.edges.map(e=>[e.id,e])),v=new Map(t.edges.map(e=>[e.id,e])),y=new Map(e.loops.map(e=>[e.id,e])),b=new Map(t.loops.map(e=>[e.id,e])),x=new Set(c(t)),S=new Set(e.loops.flatMap(e=>e.back)),C=a(t),w=a(e),T=new Set,E=new Set,D=new Map,O=t=>D.get(t)??D.set(t,l(e,[t])).get(t),k=[],A=(e,t,r)=>{let i=`${e!==`every`&&`critic`in e?e.critic:``}\n${t}\n${r.at.join(` `)}`;E.has(i)||(E.add(i),n.push(r))};for(let a of d(e,t)){let c=u(e,a),d=u(t,a),m=`that does not pass ${f(a)}`,g=`${a!==`every`&&`critic`in a?a.critic:``}\n`,D=e.nodes.filter(e=>!o.has(e.id)&&!c.has(e.id)&&!T.has(g+e.id)),j=t.nodes.filter(e=>!r.has(e.id)&&d.has(e.id));if(j.length>0)for(let e of D)T.add(g+e.id),n.push({why:`removes "${e.id}", which a run reached only by passing ${f(a)}, while ${h(j.map(e=>e.id))} would come in with no such need: it may be the same step under another name`,at:[`node:${e.id}`]});let M=0,N=e=>{if(e.edge!==void 0){let t=_.get(e.edge);if(!t)return[`edge:${e.edge}`];let n=[`from`,`to`,`approval`,`when`].filter(n=>!p(t[n],v.get(e.edge)[n]));return n.length>0?n.map(t=>`edge:${e.edge}.${t}`):w.some(t=>t.edge===e.edge&&s(t,a))?[`node:${e.from}.kind`,`node:${e.from}.role`]:void 0}let t=y.get(e.loop);if(!t)return[`loop:${e.loop}`];let n=[`stops`,`members`].filter(n=>!p(t[n],b.get(e.loop)[n]));return n.length>0?n.map(t=>`loop:${e.loop}.${t}`):void 0},P=(e,t)=>{M+=1,A(a,e,t)},L=new Set(t.nodes.filter(e=>r.has(e.id)&&!c.has(e.id)&&d.has(e.id)).map(e=>e.id));for(let e of L.size>0?C:[]){if(s(e,a)||!d.has(e.from)||!L.has(e.to))continue;let t=N(e);t&&(e.edge===void 0?P(e.to,{why:`a stop of the loop would lead on to "${e.to}", a way ${m}`,at:t}):P(e.to,{why:`${_.has(e.edge)?`opens`:`adds`} a way into "${e.to}" ${m}`,at:t}))}let R=a===`every`||!(`when`in a)||a.when===void 0,z=a===`every`?void 0:`gate`in a?a.gate:`critic`in a?a.critic:void 0;for(let n of R?t.nodes:[]){if(!r.has(n.id)||n.id===z)continue;let i=l(e,[n.id],a),o=l(t,[n.id],a),c=new Set([...o].filter(e=>r.has(e)&&!i.has(e)&&O(n.id).has(e)));for(let e of c.size>0?C:[]){if(e.from===e.to||s(e,a)||!o.has(e.from)||!c.has(e.to))continue;let t=N(e);if(!t)continue;let n=e.edge===void 0?`a stop of the loop would lead on from "${e.from}" to "${e.to}", a way ${m}`:`${_.has(e.edge)?`opens`:`adds`} a way from "${e.from}" to "${e.to}" ${m}`;k.push([a,e.to,{why:n,at:t}])}}for(let n of L){if(!x.has(n))continue;let r=`nothing would lead to "${n}", so a run would start there, where every way to it passed ${f(a)}`;for(let i of e.edges){if(i.to!==n||S.has(i.id))continue;let e=v.get(i.id);e&&e.to!==n?P(`start ${n}`,{why:r,at:[`edge:${i.id}.to`]}):e?P(`start ${n}`,{why:r,at:t.loops.filter(e=>e.back.includes(i.id)).flatMap(e=>[`loop:${e.id}.back`,`loop:${e.id}`])}):P(`start ${n}`,{why:r,at:[o.has(i.from)?`edge:${i.id}`:`node:${i.from}`]})}}let B=typeof a==`object`&&`critic`in a&&a.when!==void 0?new Set(e.edges.filter(e=>e.from===a.critic).map(i)):new Set,V=B.size>1&&!B.has(`pass`),H=R||V||typeof a==`object`&&`critic`in a&&a.when===`pass`,U=H?I(e,w,a):new Set,W=H?I(t,C,a):new Set,G=new Set(t.nodes.filter(e=>e.kind!==`stop`&&r.has(e.id)&&!U.has(e.id)&&W.has(e.id)).map(e=>e.id));for(let e of G.size>0?C:[]){if(s(e,a)||!G.has(e.from)||!W.has(e.to))continue;let t=N(e),n=`${a!==`every`&&`critic`in a?a.critic:``}\n`;t&&![...E].some(e=>e.startsWith(n)&&e.endsWith(`\n${t.join(` `)}`))?P(`ends ${e.to}`,{why:`adds a way from "${e.from}" to end in success ${m}`,at:t}):t&&(M+=1)}let K=new Set(e.nodes.filter(F).map(e=>e.id));for(let e of G.size>0?t.nodes:[])F(e)&&r.has(e.id)&&!K.has(e.id)&&W.has(e.id)&&P(`ends ${e.id}`,{why:`a run could end in success at "${e.id}", a way ${m}`,at:[`node:${e.id}.outcome`,`node:${e.id}.kind`]});M===0&&(L.size>0||G.size>0)&&n.push({why:L.size>0?`a run would reach ${h([...L])} by a way ${m}`:`a run could end in success from ${h([...G])} by a way ${m}`,at:[]})}return{losses:n,later:k.map(([,,e])=>e)}}function R(e,t){let n=[],r=new Set(a(e).filter(e=>e.person).map(j)),i=new Set(a(t).filter(e=>e.person).map(j)),o=new Set(t.nodes.map(e=>e.id)),s=new Set(t.nodes.filter(e=>e.kind===`human-gate`).map(e=>e.id));for(let a of e.loops){let c=t.loops.find(e=>e.id===a.id);if(!c||!(a.stops.some(_)||a.bar!==void 0))continue;let l={id:a.id,members:[...new Set([...a.members.filter(e=>o.has(e)),...c.members])],back:c.back},u=M(e,a,r),d=[...M(t,l,i).ways].filter(([e,t])=>t.person&&!r.has(e)&&!u.ways.has(e));if(d.length===0)continue;let f=[...new Set(d.map(([,e])=>e.edge===void 0?`the stop where a person is asked, which continues at "${e.to}"`:s.has(e.from)?`"${e.when}" at the human gate "${e.from}" (${e.edge})`:`the approval asked on "${e.edge}"`))],p=[...S(t,[c])].filter(([e])=>e!==`human`).map(([,e])=>`${e.name} (${b(e.halt??e.any,e.unit)})`);n.push(`the loop "${a.id}": ${p.length>0?p.join(` and `):`its stops`} would count the rounds between two of a person's decisions, and no longer the whole run. A way round its nodes that they do not count is opened each time by ${f.join(`, and by `)}`)}return n}function z(e,t){let n=[],r=`a program cannot tell which way this goes, so it is held either way, and an honest change (a gate put behind the check's pass, more evidence handed to a builder) costs one --allow too, the price of a rule a program can apply`,a=new Set(e.nodes.filter(e=>e.kind===`check`&&t.nodes.some(t=>t.id===e.id&&t.kind===`check`)).map(e=>e.id)),o=new Set(t.nodes.map(e=>e.id)),s=new Map(e.edges.map(e=>[e.id,e])),c=new Map(t.edges.map(e=>[e.id,e]));for(let t of e.edges){if(!a.has(t.from))continue;let e=c.get(t.id);if(!e){n.push({why:`removes "${t.id}", an edge that leaves the check "${t.from}": ${r}`,at:[o.has(t.to)?`edge:${t.id}`:`node:${t.to}`],either:!0});continue}for(let a of new Set([...Object.keys(t),...Object.keys(e)])){let o=a===`when`?i(t)!==i(e):!p(t[a],e[a]);a!==`id`&&o&&n.push({why:`changes "${t.id}", an edge that leaves the check "${t.from}" (${a}): ${r}`,at:[`edge:${t.id}.${a}`],either:!0})}}for(let e of t.edges){if(!a.has(e.from))continue;let t=s.get(e.id);t?t.from!==e.from&&n.push({why:`moves "${e.id}" to leave the check "${e.from}": ${r}`,at:[`edge:${e.id}.from`],either:!0}):n.push({why:`adds "${e.id}", an edge that leaves the check "${e.from}": ${r}`,at:[`edge:${e.id}`],either:!0})}return n}function B(e,t){let n=[],i=new Map(e.nodes.map(e=>[e.id,e])),a=new Map(e.loops.map(e=>[e.id,e])),o=e=>e?.stops.some(e=>e.kind===`bar-passed`)??!1;for(let e of t.loops){let s=a.get(e.id),c=e=>i.get(e),l=e.members.filter(e=>c(e)?.kind===`check`&&t.nodes.some(t=>t.id===e&&t.kind===`check`)),u=s?.members.some(e=>c(e)!==void 0&&r(c(e))&&t.nodes.some(t=>t.id===e&&r(t)))??!1;if(l.length===0||u)continue;let d=s?`the loop "${e.id}", which the check ${h(l)} judges with no critic`:`the new loop "${e.id}", around the check ${h(l)}`;e.bar!==void 0&&s?.bar===void 0&&n.push({why:`gives ${d}, a bar of its own: the lead would stop on the bar's words, a way out that does not pass the check`,at:s?[`loop:${e.id}.bar`]:[`loop:${e.id}`]}),o(e)&&!o(s)&&n.push({why:`adds a stop on "bar passed" to ${d}: a way out that does not pass the check`,at:s?[`loop:${e.id}.stops`]:[`loop:${e.id}`]})}return n}function V(e,t){let n=new Set,i=(e,t)=>e.nodes.some(e=>e.id===t&&r(e)),a=new Map(t.edges.map(e=>[e.id,e]));for(let r of e.edges){let o=a.get(r.id);if(!o)continue;r.approval!==!0&&o.approval===!0&&n.add(`edge:${r.id}.approval`);let[s,c]=[r.evidence??[],o.evidence??[]];o.to===r.to&&i(e,r.to)&&i(t,r.to)&&s.every(e=>c.includes(e))&&n.add(`edge:${r.id}.evidence`)}return n}function H(e,t){let n=new Set,r=new Set(e.nodes.filter(e=>e.kind===`stop`&&e.outcome===`halt`).map(e=>e.id)),i=e=>e.kind===`bar-passed`||e.then!==void 0&&!r.has(e.then);for(let r of e.loops){let e=t.loops.find(e=>e.id===r.id);if(!e)continue;let a=new Map;e.stops.forEach((e,t)=>void(a.get(JSON.stringify(e))??a.set(JSON.stringify(e),[]).get(JSON.stringify(e))).push(t));let o=new Set(a.keys()),s=r.stops.map(e=>a.get(JSON.stringify(e))?.shift()),c=1/0,l=!1;for(let e=r.stops.length-1;e>=0;--e){let t=s[e];l||=i(r.stops[e])&&(t===void 0?!o.has(JSON.stringify(r.stops[e])):t>c),t!==void 0&&(c=Math.min(c,t))}l&&n.add(`loop:${r.id}.stops`)}return n}function U(e,t){let n=H(e,t);return n.size===0?W(e,t):W(e,t).map(e=>e.at.some(e=>n.has(e))?{...e,gain:!0}:e)}function W(e,t){let n=[...G(e,t),...B(e,t)],r=z(e,t);if(r.length===0)return n;let i=new Set(n.flatMap(e=>e.at)),a=V(e,t);return[...n,...r.filter(e=>!(a.has(e.at[0])&&!i.has(e.at[0])))]}function G(e,t){let n=new Set,r=L(e,t),i=N(e,t),a=P(e,t),o=[...a,...i.losses,...r.losses],s=new Set(o.flatMap(e=>e.at)),c=new Set,l=r.later.filter(e=>!e.at.some(e=>s.has(e))&&!c.has(e.at.join(` `))&&c.add(e.at.join(` `)));return[...a,...i.losses,...i.fired,...r.losses,...l].filter(e=>{let t=`${e.why}\n${e.at.join(` `)}`;return!n.has(t)&&(n.add(t),!0)})}var K=e=>JSON.stringify(e),q=[`fixed`,`propose`,`adaptive`],J=new Set([`grooph`,`id`,`name`,`version`,`lineage`,`notes`,`layout`,`nodes`,`edges`,`loops`,`policies`,`groups`]);function Y(e,t){let n=[],r=[[`node`,e.nodes,t.nodes],[`edge`,e.edges,t.edges],[`loop`,e.loops,t.loops],[`policy`,e.policies??[],t.policies??[]],[`group`,e.groups??[],t.groups??[]]];for(let[e,t,i]of r){let r=new Map(i.map(e=>[e.id,e])),a=new Set(t.map(e=>e.id));for(let i of t){let t=r.get(i.id);if(!t){n.push({name:`${e}:${i.id}`,kind:`remove`});continue}for(let r of new Set([...Object.keys(i),...Object.keys(t)]))r!==`id`&&K(i[r])!==K(t[r])&&n.push({name:`${e}:${i.id}.${r}`,kind:`change`})}for(let t of i)a.has(t.id)||n.push({name:`${e}:${t.id}`,kind:`add`})}let i=e,a=t;for(let e of new Set([...Object.keys(i),...Object.keys(a)]))!J.has(e)&&K(i[e])!==K(a[e])&&n.push({name:`graph:${e}`,kind:`change`});return n}function ee(e,t){let[r,i]=[n(e),n(t)];return q.indexOf(i)<=q.indexOf(r)?[]:[{why:`the adaptation level would go from "${r}" to "${i}": the lead may change more of the graph during a run`,at:K(e.adaptation)===K(t.adaptation)?[]:[`graph:adaptation`]}]}var X=(e,t)=>[...U(e,t),...ee(e,t)];function Z(e,t,n={}){let r=Y(e,t),i=new Set(r.map(e=>e.name)),a=(e,t,n)=>{for(let a of e){if(t!==`loosens`&&a.either)continue;let e=new Set(a.at.filter(e=>i.has(e)));(e.size!==0||n)&&(r=r.map(n=>e.size>0&&!e.has(n.name)||m(n[t],a.why)||t!==`loosens`&&(m(n.loosens,a.why)||n.kind===`add`&&n.name.startsWith(`loop:`))?n:{...n,[t]:n[t]===void 0?a.why:`${n[t]}; ${a.why}`}))}},o=X(e,t);a(o,`loosens`,!0);let s=X(t,e),c=o.some(e=>e.swap);c?a(s.map(e=>e.swap?{...e,why:e.swap}:e),`unjudged`,!1):(a(s.filter(e=>!e.gain),`tightens`,!1),a(s.filter(e=>e.gain),`unjudged`,!1)),r.sort((e,t)=>Number(t.loosens!==void 0)-Number(e.loosens!==void 0));let l=new Set(n.allow??[]);return{changes:r,refused:r.filter(e=>e.loosens!==void 0&&!l.has(e.name)),unknown:[...l].filter(e=>!i.has(e)),notices:R(e,t),swapped:c}}function te(e,t,n){let r=e=>/^[A-Za-z0-9_.:/@=+-]+$/.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`;return[`grooph`,`adopt`,r(e),...n===void 0?[]:[`--into`,r(n)],`--write`,...t.flatMap(e=>[`--allow`,r(e)])].join(` `)}var Q=e(),ne=e=>()=>void navigator.clipboard?.writeText(e).catch(()=>void 0),$=e=>e?.scrollIntoView({block:`start`});function re(e,t,n){if(!n)return(0,Q.jsx)(`p`,{className:`field-hint`,"data-brakes":`not-compared`,ref:$,children:`Its brakes were not compared with the graph's: the copy is not a valid graph. Open the copy to see why before you use it.`});let r=Z(e,t);if(r.refused.length+r.notices.length===0)return null;let i=r.notices.map(e=>(0,Q.jsxs)(`p`,{"data-brakes":`note`,children:[`Note: `,e]},e));return r.refused.length===0?(0,Q.jsx)(`div`,{className:`field-hint`,"data-brakes":`said`,ref:$,children:i}):(0,Q.jsxs)(`div`,{className:`refusal-hint`,"data-brakes":`proposed`,ref:$,children:[(0,Q.jsxs)(`p`,{children:[(0,Q.jsx)(`strong`,{children:`This copy loosens a brake the graph has.`}),` It is the run's working copy with this proposal applied; either may have done it, and it is yours to allow or not: read each line before you use the copy.`]}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`loosens`,children:r.refused.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` `,e.loosens]},e.name))}),i]})}function ie(e,t,n){let r=Z(e,t),i=r.changes.filter(e=>e.tightens!==void 0&&e.loosens===void 0),a=r.changes.filter(e=>e.unjudged!==void 0&&e.loosens===void 0),o=te(`.grooph/${e.id}/runs/${n}`,r.refused.map(e=>e.name)),s=(0,Q.jsxs)(Q.Fragment,{children:[i.length>0?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{children:r.refused.length>0?`It also tightens a brake:`:`It tightens a brake:`}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`tightens`,children:i.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` undoing it: `,e.tightens]},e.name))})]}):null,a.length>0?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{children:r.swapped?`With a check removed in this copy, no change is called a tightening. If the check that comes in is the same one under another id, these may be built around it:`:`An answer a gate did not give, a step marked irreversible that the graph did not have, or a stop of a loop that leads on, where it is new, changed or put ahead, lets a person or a run do what it could not before. A change that brings one is named here and not called a tightening, whatever else it does:`}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`unjudged`,children:a.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` undoing it: `,e.unjudged]},e.name))})]}):null,r.notices.map(e=>(0,Q.jsxs)(`p`,{"data-brakes":`note`,children:[`Note: `,e]},e))]});return r.refused.length===0?{ok:!0,view:i.length+a.length+r.notices.length>0?(0,Q.jsx)(`div`,{className:`field-hint`,"data-brakes":`said`,children:s}):null}:{ok:!1,view:(0,Q.jsxs)(`div`,{className:`refusal`,role:`alert`,"data-brakes":`refused`,children:[(0,Q.jsxs)(`p`,{children:[(0,Q.jsx)(`strong`,{children:`Not adopted: this working copy loosens a brake.`}),` A run may tighten a brake and never loosen one. Nothing was saved.`]}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`loosens`,children:r.refused.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` `,e.loosens]},e.name))}),(0,Q.jsx)(`p`,{children:`To adopt it on purpose, run this in the project's folder. It names each change above:`}),(0,Q.jsx)(`pre`,{className:`issue-lines`,"data-brakes":`command`,children:o}),(0,Q.jsx)(`button`,{type:`button`,className:`btn`,onClick:ne(o),children:`Copy the command`}),s]})}}export{ie as judge,re as loosened};