#!/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)"