cyberia/scripts/views.nu

#!/usr/bin/env nu
# views.nu — the sensors behind cyberia/views: what the graph cannot see from its pages
# (open pull requests on github, the requirement counters, receipt ages, the train)
# written as one page, cyberia/views/sensors.md. the page-based views are optica
# queries on the view pages themselves and need no script. runs hourly (to.cyberia.views).

let home = ($env.HOME | path join "cyber")
let today = (date now | format date "%Y-%m-%d")
let ladder = [[rung repo role]; [1 nox machine] [2 trident weapon] [3 joy warrior] [4 cybergraph brain] [5 neural language] [6 cy agent] [7 soft3 network] [8 cyb robot] [9 cyber superintelligence] [10 cyberia state]]

def days-since [d: string] {
  if ($d | is-empty) { return null }
  ((date now) - ($d | into datetime)) / 1day | math floor
}

# --- products: dots from the counters, receipt age from git ---
let products = ($ladder | each {|r|
  let repo = ($home | path join $r.repo)
  let audit = ($repo | path join "audit")
  let maps = (if ($audit | path exists) { glob ($audit | path join "*" "map.md") } else { [] })
  let counter = ($repo | path join "scripts" "requirements.nu")
  let dots = (if (($maps | length) > 0) and ($counter | path exists) {
    $maps | each {|m|
      let name = ($m | path dirname | path basename)
      let out = (do { cd $repo; ^nu scripts/requirements.nu --spec $"specs/($name).md" --map $"audit/($name)/map.md" --dots } | complete)
      $"($name): ($out.stdout | str trim)"
    } | str join "; "
  } else { "—" })
  let receipt = (if ($audit | path exists) { do { cd $repo; ^git log -1 --format=%cs -- audit } | complete | get stdout | str trim } else { "" })
  let age = (days-since $receipt)
  {rung: $r.rung, product: $"($r.repo) · ($r.role)", dots: $dots, receipt: (if ($receipt | is-empty) { "—" } else { $"($receipt) \(($age) d\)" }), age: $age, maps: ($maps | length)}
})

# --- pull requests ---
let prs = (^gh search prs --owner cyberia-to --state open --limit 500 --json repository,number,title,createdAt,isDraft | from json
  | each {|p| {repo: $p.repository.name, number: $p.number, title: $p.title, age: (days-since $p.createdAt), draft: $p.isDraft}})
let per_repo = ($prs | group-by repo | transpose repo items | each {|g| {repo: $g.repo, open: ($g.items | length), oldest: ($g.items | get age | math max)}} | sort-by open -r)
let old = ($prs | where age > 14 | length)

# --- the train ---
let train = (["cyb" "cyber" "soft3"] | each {|r|
  let a = ($home | path join $r "audit")
  let cands = (if ($a | path exists) { ls $a | where name =~ "release-" | get name | path basename | sort } else { [] })
  let last = (if ($cands | length) > 0 { $cands | last } else { "" })
  let d = (if ($last | is-empty) { "" } else { $last | parse -r '(\d{4})-?(\d{2})-?(\d{2})' | get 0 | $"($in.capture0)-($in.capture1)-($in.capture2)" })
  {product: $r, candidate: (if ($last | is-empty) { "—" } else { $last }), age: (days-since $d)}
})

# --- experiments: the decisions log of fathership ---
let experiments = (open --raw ($home | path join "cyberia" "projects" "fathership.md") | lines | where ($it | str starts-with "- 20") and ($it =~ "expected effect")
  | each {|l| let m = ($l | parse -r '^- (?\S+) · (?.*?)\. expected effect: (?.*?) · check: (?.*?) · outcome: (?.*)$'); if ($m | is-empty) { null } else { $m | get 0 } } | compact)

# --- alerts ---
mut alerts = []
if $old > 0 { $alerts = ($alerts | append $"($old) pull requests older than 14 days") }
for t in $train { if ($t.age == null) { $alerts = ($alerts | append $"($t.product): no candidate receipts in `audit/`") } else if $t.age > 10 { $alerts = ($alerts | append $"($t.product): last candidate ($t.age) days ago") } }
for p in $products { if ($p.age == null) { $alerts = ($alerts | append $"($p.product | str replace -r '\[\[(\w+)\]\].*' '$1'): no receipt in `audit/`") } else if $p.age > 14 { $alerts = ($alerts | append $"(MATH_PLACEHOLDER_401'): last receipt ($p.age) days ago") } }
let nomap = (MATH_PLACEHOLDER_411' })
if ($nomap | length) > 0 { $alerts = ($alerts | append $"($nomap | length) of 10 products have no requirement map: ($nomap | str join ', ')") }

def md-table [rows: list, cols: list] {
  let head = $"| ($cols | str join ' | ') |"
  let sep = $"|($cols | each { '---' } | str join '|')|"
  let body = ($rows | each {|r| $"| ($cols | each {|c| $r | get $c | default '—' | into string } | str join ' | ') |" })
  [$head $sep] | append $body | str join "\n"
}

let now = (date now | format date "%Y-%m-%d %H:%M")
let page = [
  "---" "title: views · sensors" "tags: cyber, cyberia, views, generated" "alias: views sensors, sensors, the sensors of the views" "crystal-type: measure" "crystal-domain: cyberia" "---" ""
  "# views · sensors" ""
  $"generated by `cyberia/scripts/views.nu` at ($now) UTC from github, git and the requirement counters; never edited by hand. the page-based views are queries on views." ""
  "## alerts" ""
  (if ($alerts | is-empty) { "- none" } else { $alerts | each { $"- ($in)" } | str join "\n" }) ""
  "## products" ""
  (md-table $products [rung product dots receipt]) ""
  "## pull requests, open" ""
  $"total ($prs | length) across ($per_repo | length) repositories; older than 14 days: ($old)" ""
  (md-table ($per_repo | first 15) [repo open oldest]) ""
  "oldest:" ""
  ($prs | sort-by age -r | first 8 | each {|p| $"- ($p.repo) [#($p.number)]\(https://github.com/cyberia-to/($p.repo)/pull/($p.number)\) · ($p.age) d · ($p.title | str substring 0..90)" } | str join "\n") ""
  "## the train" ""
  (md-table ($train | each {|t| {product: $t.product, candidate: $t.candidate, age: (if $t.age == null { "—" } else { $"($t.age) d" })}}) [product candidate age]) ""
  "## experiments" ""
  (if ($experiments | is-empty) { "no decision carries an expected effect yet" } else { $experiments | each {|e| $"- **($e.date)** ($e.decision | str substring 0..120) — expected: ($e.effect | str substring 0..120) · check: ($e.check | str substring 0..80) · outcome: (if ($e.outcome | is-empty) { '—' } else { $e.outcome })" } | str join "\n" }) ""
] | str join "\n"
$page | save -f ($home | path join "cyberia" "views" "sensors.md")
print $"sensors written: alerts ($alerts | length), prs ($prs | length)"

Graph