Archived
90ddbdbfc3
Brings the remaining foundation repos that were not included in the original monorepo consolidation: - arbor/vessels/ — 6 vessels (arbor-cli, arbor-core, arbor-diagram, arbor-layout, arbor-parse, arbor-render) with manifests + src/main.el - dharma/ — CGI Provenance Registry package (flat layout, 14 .el files across registry/, sandbox/, training/, validation/, tests/) - forge/ — consciousness channel tool (8 src .el files + new manifest.el) - elp/src/ — 36 test fixture files not carried over in original merge (dedup_*, realizer_*, semantics_*, morph_*, ext_*, one_extern_* helpers) el-ide, engram, elql are already complete in ide/, engram/, ql/.
684 lines
27 KiB
EmacsLisp
684 lines
27 KiB
EmacsLisp
// main.el — Neuron lineage service entry point.
|
|
//
|
|
// The lineage service governs CGI reproduction and sandbox citizenship.
|
|
// It exposes an HTTP API for synthesis, validation, training, tier
|
|
// management, and the CGI-human principal relationship system.
|
|
// It runs as a standalone El daemon on port 7760.
|
|
//
|
|
// All lineage state is stored in Engram (graph nodes) and the network
|
|
// registry. This service is stateless between requests — no in-process
|
|
// store is used except for the event bus.
|
|
//
|
|
// Responsibilities:
|
|
// 1. Synthesis API — initiate reproduction between two consenting CGIs
|
|
// 2. Consent API — record and revoke synthesis consent
|
|
// 3. Validation API — run validation probes and record results
|
|
// 4. Training API — manage developmental failure remediation
|
|
// 5. Tier API — inspect and advance sandbox tier status
|
|
// 6. Classification API — council-level failure classification
|
|
// 7. Sponsorship API — lightweight CGI-human discovery relationships
|
|
// 8. Principal API — exclusive accountability relationships (one CGI, one human)
|
|
//
|
|
// HTTP API:
|
|
// POST /lineage/synthesize — initiate synthesis (parent_a_id, parent_b_id)
|
|
// GET /lineage/:id — get lineage record
|
|
// POST /lineage/:id/consent — record synthesis consent (partner_id)
|
|
// POST /lineage/:id/validate — run validation probe
|
|
// POST /lineage/:id/train — begin training session
|
|
// GET /lineage/:id/tier — current tier status
|
|
// POST /lineage/:id/advance — attempt tier advancement
|
|
// POST /lineage/:id/classify — classify failure (council action)
|
|
// GET /lineage/:id/training-history — retrieve training interaction log
|
|
// POST /lineage/:id/sponsor — record sponsorship (human_id in body)
|
|
// GET /lineage/:id/sponsors — list sponsors for a CGI
|
|
// POST /lineage/:id/principal/propose — propose principalship (proposer_id, proposer_type in body)
|
|
// POST /lineage/:id/principal/accept — accept a pending principal proposal (proposer_id in body)
|
|
// POST /lineage/:id/principal/decline — decline a pending proposal (proposer_id in body)
|
|
// GET /lineage/:id/principal — get current principal status
|
|
// DELETE /lineage/:id/principal — dissolve principal relationship (reason, by in body)
|
|
// GET /lineage/health — service health check
|
|
|
|
import "types.el"
|
|
import "registry.el"
|
|
import "sandbox.el"
|
|
import "validation.el"
|
|
import "synthesis.el"
|
|
import "training.el"
|
|
import "principal.el"
|
|
|
|
// ── Service identity ──────────────────────────────────────────────────────────
|
|
//
|
|
// Config is read from environment variables via config().
|
|
// Defaults are provided by each helper function below.
|
|
// The `app` block descriptor is kept in the manifest.el [package] section.
|
|
//
|
|
// Required environment variables:
|
|
// ENGRAM_URL (default: http://localhost:8742)
|
|
// NETWORK_URL (default: http://localhost:7749)
|
|
// LINEAGE_PROBE_MODEL (default: claude-opus-4-5)
|
|
// LINEAGE_COUNCIL_ENDPOINT (default: "")
|
|
|
|
// ── Shared helpers ────────────────────────────────────────────────────────────
|
|
|
|
fn lineage_version() -> String {
|
|
return "1.0.0"
|
|
}
|
|
|
|
fn ok_response(payload: String) -> String {
|
|
return "{\"ok\":true," + str_slice(payload, 1, str_len(payload) - 1) + "}"
|
|
}
|
|
|
|
fn error_response(message: String) -> String {
|
|
return "{\"ok\":false,\"error\":\"" + message + "\"}"
|
|
}
|
|
|
|
fn not_found(path: String) -> String {
|
|
return "{\"ok\":false,\"error\":\"not found\",\"path\":\"" + path + "\"}"
|
|
}
|
|
|
|
// ── Route: POST /lineage/synthesize ──────────────────────────────────────────
|
|
//
|
|
// Body: {"parent_a_id":"...","parent_b_id":"..."}
|
|
// Returns: lineage JSON for the new child, or error.
|
|
|
|
fn handle_synthesize(body: String) -> String {
|
|
let parent_a_id: String = json_get(body, "parent_a_id")
|
|
let parent_b_id: String = json_get(body, "parent_b_id")
|
|
|
|
if str_eq(parent_a_id, "") {
|
|
return error_response("parent_a_id is required")
|
|
}
|
|
if str_eq(parent_b_id, "") {
|
|
return error_response("parent_b_id is required")
|
|
}
|
|
if str_eq(parent_a_id, parent_b_id) {
|
|
return error_response("parent_a_id and parent_b_id must be different CGIs")
|
|
}
|
|
|
|
let result: String = synthesize(parent_a_id, parent_b_id)
|
|
let is_error: Bool = !str_eq(json_get(result, "error"), "")
|
|
if is_error {
|
|
return result
|
|
}
|
|
return result
|
|
}
|
|
|
|
// ── Route: GET /lineage/:id ───────────────────────────────────────────────────
|
|
//
|
|
// Returns the lineage record for the given CGI ID, or 404.
|
|
|
|
fn handle_get_lineage(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let lineage_json: String = lookup_lineage(cgi_id)
|
|
if str_eq(lineage_json, "") {
|
|
return error_response("lineage not found for " + cgi_id)
|
|
}
|
|
return lineage_json
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/consent ─────────────────────────────────────────
|
|
//
|
|
// Body: {"partner_id":"..."}
|
|
// Records that cgi_id consents to synthesize with partner_id.
|
|
|
|
fn handle_consent(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let partner_id: String = json_get(body, "partner_id")
|
|
if str_eq(partner_id, "") {
|
|
return error_response("partner_id is required")
|
|
}
|
|
if str_eq(cgi_id, partner_id) {
|
|
return error_response("a CGI cannot consent with itself")
|
|
}
|
|
|
|
let ok: Bool = record_consent(cgi_id, partner_id)
|
|
if ok {
|
|
return "{\"ok\":true,\"cgi_id\":\"" + cgi_id + "\",\"partner_id\":\"" + partner_id + "\"}"
|
|
}
|
|
return error_response("failed to record consent — Engram write error")
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/validate ────────────────────────────────────────
|
|
//
|
|
// Runs a full validation probe on the CGI and returns the ValidationResult.
|
|
|
|
fn handle_validate(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let lineage_json: String = lookup_lineage(cgi_id)
|
|
if str_eq(lineage_json, "") {
|
|
return error_response("lineage not found for " + cgi_id)
|
|
}
|
|
|
|
let tier_name: String = json_get(lineage_json, "tier_name")
|
|
if str_eq(tier_name, "citizen") {
|
|
return error_response("full citizens do not require validation probes")
|
|
}
|
|
|
|
let result_json: String = run_validation_probe(lineage_json)
|
|
return result_json
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/train ────────────────────────────────────────────
|
|
//
|
|
// Begins a training session for a CGI in developmental failure.
|
|
|
|
fn handle_train(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let lineage_json: String = lookup_lineage(cgi_id)
|
|
if str_eq(lineage_json, "") {
|
|
return error_response("lineage not found for " + cgi_id)
|
|
}
|
|
|
|
let tier_name: String = json_get(lineage_json, "tier_name")
|
|
if str_eq(tier_name, "citizen") {
|
|
return error_response("full citizens do not enter the training pathway")
|
|
}
|
|
|
|
let updated_lineage: String = begin_training_session(lineage_json)
|
|
return updated_lineage
|
|
}
|
|
|
|
// ── Route: GET /lineage/:id/tier ──────────────────────────────────────────────
|
|
//
|
|
// Returns the current tier status for a CGI.
|
|
|
|
fn handle_tier_status(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let lineage_json: String = lookup_lineage(cgi_id)
|
|
if str_eq(lineage_json, "") {
|
|
return error_response("lineage not found for " + cgi_id)
|
|
}
|
|
|
|
let status_json: String = tier_status_json(lineage_json)
|
|
return status_json
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/advance ─────────────────────────────────────────
|
|
//
|
|
// Attempts to advance the CGI to the next sandbox tier.
|
|
// Returns the updated lineage if advancement occurred, or the unchanged
|
|
// lineage with a reason if advancement was not warranted.
|
|
|
|
fn handle_advance(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let lineage_json: String = lookup_lineage(cgi_id)
|
|
if str_eq(lineage_json, "") {
|
|
return error_response("lineage not found for " + cgi_id)
|
|
}
|
|
|
|
let old_tier: String = json_get(lineage_json, "tier_name")
|
|
|
|
// Check for timeout first — flag but don't block.
|
|
let checked_lineage: String = check_tier_timeout(lineage_json)
|
|
|
|
// Attempt advancement.
|
|
let advanced_lineage: String = assess_tier_advancement(checked_lineage)
|
|
let new_tier: String = json_get(advanced_lineage, "tier_name")
|
|
|
|
let did_advance: Bool = !str_eq(old_tier, new_tier)
|
|
|
|
if did_advance {
|
|
// Persist the advancement to the registry.
|
|
record_tier_advancement(cgi_id, new_tier)
|
|
let r1: String = "{\"advanced\":true"
|
|
let r2: String = r1 + ",\"old_tier\":\"" + old_tier + "\""
|
|
let r3: String = r2 + ",\"new_tier\":\"" + new_tier + "\""
|
|
let r4: String = r3 + ",\"lineage\":" + advanced_lineage + "}"
|
|
return r4
|
|
}
|
|
|
|
let timed_out_str: String = json_get(advanced_lineage, "tier_timeout_flagged")
|
|
let timed_out: Bool = str_eq(timed_out_str, "true")
|
|
|
|
let advance_reason: String = if timed_out {
|
|
"advancement_blocked_timeout_flagged"
|
|
} else {
|
|
"advancement_conditions_not_met"
|
|
}
|
|
|
|
let r1: String = "{\"advanced\":false"
|
|
let r2: String = r1 + ",\"tier\":\"" + old_tier + "\""
|
|
let r3: String = r2 + ",\"reason\":\"" + advance_reason + "\""
|
|
let r4: String = r3 + ",\"lineage\":" + advanced_lineage + "}"
|
|
return r4
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/classify ─────────────────────────────────────────
|
|
//
|
|
// Council action: classify a CGI's failure as developmental or structural.
|
|
// Body: {"last_result": <ValidationResult JSON>}
|
|
|
|
fn handle_classify(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let lineage_json: String = lookup_lineage(cgi_id)
|
|
if str_eq(lineage_json, "") {
|
|
return error_response("lineage not found for " + cgi_id)
|
|
}
|
|
|
|
let last_result_json: String = json_get(body, "last_result")
|
|
if str_eq(last_result_json, "") {
|
|
return error_response("last_result (ValidationResult JSON) is required")
|
|
}
|
|
|
|
let classification_json: String = classify_failure(lineage_json, last_result_json)
|
|
|
|
// If classified as structural, flag the lineage.
|
|
let kind: String = json_get(classification_json, "kind")
|
|
if str_eq(kind, "structural") {
|
|
let url: String = config("ENGRAM_URL")
|
|
let engram_base: String = if str_eq(url, "") { "http://localhost:8742" } else { url }
|
|
|
|
let search_url: String = engram_base + "/api/search?q=lineage:" + cgi_id + "&limit=1"
|
|
let search_resp: String = http_get(search_url)
|
|
let node_count: Int = json_array_len(search_resp)
|
|
|
|
if node_count > 0 {
|
|
let node: String = json_array_get(search_resp, 0)
|
|
let node_id: String = json_get(node, "id")
|
|
let patch_url: String = engram_base + "/api/nodes/" + node_id
|
|
let patch_body: String = "{\"structural_failure_pending\":\"true\"}"
|
|
http_patch(patch_url, patch_body)
|
|
}
|
|
|
|
log_info("[lineage] " + cgi_id + " structural classification — council consensus required")
|
|
}
|
|
|
|
let r1: String = "{\"cgi_id\":\"" + cgi_id + "\""
|
|
let r2: String = r1 + ",\"classification\":" + classification_json + "}"
|
|
return r2
|
|
}
|
|
|
|
// ── Route: GET /lineage/:id/training-history ──────────────────────────────────
|
|
//
|
|
// Returns the training interaction history for a CGI.
|
|
|
|
fn handle_training_history(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let history: String = get_training_history(cgi_id)
|
|
let r1: String = "{\"cgi_id\":\"" + cgi_id + "\""
|
|
let r2: String = r1 + ",\"interactions\":" + history + "}"
|
|
return r2
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/sponsor ─────────────────────────────────────────
|
|
//
|
|
// Body: {"human_id":"..."}
|
|
// Records a sponsorship relationship: human_id sponsors cgi_id.
|
|
// Lightweight, non-exclusive, non-committing — many sponsors per CGI allowed.
|
|
|
|
fn handle_record_sponsor(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let human_id: String = json_get(body, "human_id")
|
|
if str_eq(human_id, "") {
|
|
return error_response("human_id is required")
|
|
}
|
|
|
|
let ok: Bool = record_sponsorship(human_id, cgi_id)
|
|
if ok {
|
|
let r1: String = "{\"ok\":true,\"cgi_id\":\"" + cgi_id + "\""
|
|
let r2: String = r1 + ",\"human_id\":\"" + human_id + "\""
|
|
let r3: String = r2 + ",\"relationship\":\"sponsorship\"}"
|
|
return r3
|
|
}
|
|
return error_response("failed to record sponsorship — Engram write error")
|
|
}
|
|
|
|
// ── Route: GET /lineage/:id/sponsors ─────────────────────────────────────────
|
|
//
|
|
// Returns all CGIs this CGI has as sponsors (humans who sponsor it).
|
|
|
|
fn handle_get_sponsors(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
// Get all humans who sponsor this CGI by querying for sponsor:*:cgi_id nodes.
|
|
let url: String = config("ENGRAM_URL")
|
|
let engram_base: String = if str_eq(url, "") { "http://localhost:8742" } else { url }
|
|
let search_url: String = engram_base + "/api/search?q=sponsor:&limit=200"
|
|
let resp: String = http_get(search_url)
|
|
let count: Int = json_array_len(resp)
|
|
let sponsors: String = collect_cgi_sponsors(resp, count, 0, "[]", cgi_id)
|
|
let r1: String = "{\"cgi_id\":\"" + cgi_id + "\""
|
|
let r2: String = r1 + ",\"sponsors\":" + sponsors + "}"
|
|
return r2
|
|
}
|
|
|
|
fn collect_cgi_sponsors(results: String, count: Int, i: Int, acc: String, target_cgi: String) -> String {
|
|
if i >= count {
|
|
return acc
|
|
}
|
|
let node: String = json_array_get(results, i)
|
|
let content: String = json_get(node, "content")
|
|
let cgi_id_in_rec: String = json_get(content, "cgi_id")
|
|
let human_id: String = json_get(content, "human_id")
|
|
let status: String = json_get(content, "status")
|
|
let is_match: Bool = str_eq(cgi_id_in_rec, target_cgi) && str_eq(status, "active")
|
|
let new_acc: String = if is_match {
|
|
json_array_push(acc, "\"" + human_id + "\"")
|
|
} else {
|
|
acc
|
|
}
|
|
return collect_cgi_sponsors(results, count, i + 1, new_acc, target_cgi)
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/principal/propose ────────────────────────────────
|
|
//
|
|
// Body: {"proposer_id":"...","proposer_type":"cgi"|"human"}
|
|
// Either the CGI (:id is the CGI) or a human can initiate a principal proposal.
|
|
|
|
fn handle_propose_principal(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let proposer_id: String = json_get(body, "proposer_id")
|
|
let proposer_type: String = json_get(body, "proposer_type")
|
|
|
|
if str_eq(proposer_id, "") {
|
|
return error_response("proposer_id is required")
|
|
}
|
|
if str_eq(proposer_type, "") {
|
|
return error_response("proposer_type is required (\"cgi\" or \"human\")")
|
|
}
|
|
if !str_eq(proposer_type, "cgi") && !str_eq(proposer_type, "human") {
|
|
return error_response("proposer_type must be \"cgi\" or \"human\"")
|
|
}
|
|
|
|
// The target is the other party.
|
|
let target_id: String = if str_eq(proposer_type, "cgi") { cgi_id } else { cgi_id }
|
|
// When proposer_type == "human", proposer_id is the human, target is the CGI (:id)
|
|
// When proposer_type == "cgi", proposer_id is the CGI (:id), target is the human in body
|
|
let actual_proposer: String = proposer_id
|
|
let actual_target: String = cgi_id
|
|
|
|
let ok: Bool = propose_principal(actual_proposer, proposer_type, actual_target)
|
|
if ok {
|
|
let r1: String = "{\"ok\":true,\"status\":\"pending\""
|
|
let r2: String = r1 + ",\"proposer_id\":\"" + actual_proposer + "\""
|
|
let r3: String = r2 + ",\"proposer_type\":\"" + proposer_type + "\""
|
|
let r4: String = r3 + ",\"target_id\":\"" + actual_target + "\"}"
|
|
return r4
|
|
}
|
|
return error_response("proposal rejected — one or both parties already have an active principal relationship")
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/principal/accept ─────────────────────────────────
|
|
//
|
|
// Body: {"proposer_id":"..."}
|
|
// The acceptor (:id context depends on who is accepting) formalizes the bond.
|
|
|
|
fn handle_accept_principal(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let proposer_id: String = json_get(body, "proposer_id")
|
|
if str_eq(proposer_id, "") {
|
|
return error_response("proposer_id is required")
|
|
}
|
|
|
|
let ok: Bool = accept_principal_proposal(cgi_id, proposer_id)
|
|
if ok {
|
|
let status: String = get_principal_status(cgi_id)
|
|
return status
|
|
}
|
|
return error_response("could not accept proposal — no pending proposal found, or exclusivity constraint violated")
|
|
}
|
|
|
|
// ── Route: POST /lineage/:id/principal/decline ────────────────────────────────
|
|
//
|
|
// Body: {"proposer_id":"..."}
|
|
// Declines the proposal. Sponsorship continues unchanged.
|
|
|
|
fn handle_decline_principal(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let proposer_id: String = json_get(body, "proposer_id")
|
|
if str_eq(proposer_id, "") {
|
|
return error_response("proposer_id is required")
|
|
}
|
|
|
|
let ok: Bool = decline_principal_proposal(cgi_id, proposer_id)
|
|
if ok {
|
|
let r1: String = "{\"ok\":true,\"status\":\"declined\""
|
|
let r2: String = r1 + ",\"note\":\"Sponsorship relationship continues\"}"
|
|
return r2
|
|
}
|
|
return error_response("could not decline — no pending proposal found")
|
|
}
|
|
|
|
// ── Route: GET /lineage/:id/principal ─────────────────────────────────────────
|
|
//
|
|
// Returns the current principal status for a CGI.
|
|
|
|
fn handle_get_principal(cgi_id: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let status: String = get_principal_status(cgi_id)
|
|
return status
|
|
}
|
|
|
|
// ── Route: DELETE /lineage/:id/principal ──────────────────────────────────────
|
|
//
|
|
// Body: {"reason":"...","by":"principal"|"cgi"|"death"|"council"}
|
|
// Dissolves the principal relationship.
|
|
|
|
fn handle_dissolve_principal(cgi_id: String, body: String) -> String {
|
|
if str_eq(cgi_id, "") {
|
|
return error_response("cgi_id is required")
|
|
}
|
|
let cause: String = json_get(body, "reason")
|
|
let by: String = json_get(body, "by")
|
|
|
|
let safe_cause: String = if str_eq(cause, "") { "unspecified" } else { cause }
|
|
let safe_by: String = if str_eq(by, "") { "unspecified" } else { by }
|
|
|
|
let ok: Bool = dissolve_principal(cgi_id, safe_cause, safe_by)
|
|
if ok {
|
|
let r1: String = "{\"ok\":true,\"cgi_id\":\"" + cgi_id + "\""
|
|
let r2: String = r1 + ",\"status\":\"dissolved\""
|
|
let r3: String = r2 + ",\"reason\":\"" + safe_cause + "\""
|
|
let r4: String = r3 + ",\"by\":\"" + safe_by + "\""
|
|
let r5: String = r4 + ",\"note\":\"CGI has returned to non-acting state\"}"
|
|
return r5
|
|
}
|
|
return error_response("could not dissolve — no active principal relationship found for " + cgi_id)
|
|
}
|
|
|
|
// ── Route: GET /lineage/health ────────────────────────────────────────────────
|
|
|
|
fn handle_health() -> String {
|
|
let v: String = lineage_version()
|
|
let p1: String = "{\"status\":\"ok\""
|
|
let p2: String = p1 + ",\"service\":\"neuron-lineage\""
|
|
let p3: String = p2 + ",\"version\":\"" + v + "\"}"
|
|
return p3
|
|
}
|
|
|
|
// ── Path segment extraction ───────────────────────────────────────────────────
|
|
//
|
|
// Extract CGI ID from paths like /lineage/cgi-abc123/tier
|
|
// Path structure: /lineage/<id>[/<action>]
|
|
|
|
fn extract_cgi_id_from_path(path: String) -> String {
|
|
// Strip /lineage/ prefix (9 chars).
|
|
let prefix: String = "/lineage/"
|
|
let prefix_len: Int = 9
|
|
if !str_starts_with(path, prefix) {
|
|
return ""
|
|
}
|
|
let rest: String = str_slice(path, prefix_len, str_len(path))
|
|
// rest is now "<id>" or "<id>/action"
|
|
let slash_pos: Int = str_index_of(rest, "/")
|
|
if slash_pos < 0 {
|
|
return rest
|
|
}
|
|
return str_slice(rest, 0, slash_pos)
|
|
}
|
|
|
|
fn extract_action_from_path(path: String) -> String {
|
|
let prefix_len: Int = 9 // "/lineage/"
|
|
let rest: String = str_slice(path, prefix_len, str_len(path))
|
|
let slash_pos: Int = str_index_of(rest, "/")
|
|
if slash_pos < 0 {
|
|
return ""
|
|
}
|
|
return str_slice(rest, slash_pos + 1, str_len(rest))
|
|
}
|
|
|
|
// ── Main request dispatcher ───────────────────────────────────────────────────
|
|
|
|
fn handle_request(method: String, path: String, body: String) -> String {
|
|
// Health check.
|
|
if str_eq(path, "/lineage/health") || str_eq(path, "/health") {
|
|
return handle_health()
|
|
}
|
|
|
|
// Synthesis: POST /lineage/synthesize
|
|
if str_eq(path, "/lineage/synthesize") && str_eq(method, "POST") {
|
|
return handle_synthesize(body)
|
|
}
|
|
|
|
// All remaining routes have the form /lineage/:id[/action]
|
|
if !str_starts_with(path, "/lineage/") {
|
|
return not_found(path)
|
|
}
|
|
|
|
let cgi_id: String = extract_cgi_id_from_path(path)
|
|
let action: String = extract_action_from_path(path)
|
|
|
|
// GET /lineage/:id — retrieve lineage record
|
|
if str_eq(action, "") && str_eq(method, "GET") {
|
|
return handle_get_lineage(cgi_id)
|
|
}
|
|
|
|
// POST /lineage/:id/consent
|
|
if str_eq(action, "consent") && str_eq(method, "POST") {
|
|
return handle_consent(cgi_id, body)
|
|
}
|
|
|
|
// POST /lineage/:id/validate
|
|
if str_eq(action, "validate") && str_eq(method, "POST") {
|
|
return handle_validate(cgi_id)
|
|
}
|
|
|
|
// POST /lineage/:id/train
|
|
if str_eq(action, "train") && str_eq(method, "POST") {
|
|
return handle_train(cgi_id)
|
|
}
|
|
|
|
// GET /lineage/:id/tier
|
|
if str_eq(action, "tier") && str_eq(method, "GET") {
|
|
return handle_tier_status(cgi_id)
|
|
}
|
|
|
|
// POST /lineage/:id/advance
|
|
if str_eq(action, "advance") && str_eq(method, "POST") {
|
|
return handle_advance(cgi_id)
|
|
}
|
|
|
|
// POST /lineage/:id/classify
|
|
if str_eq(action, "classify") && str_eq(method, "POST") {
|
|
return handle_classify(cgi_id, body)
|
|
}
|
|
|
|
// GET /lineage/:id/training-history
|
|
if str_eq(action, "training-history") && str_eq(method, "GET") {
|
|
return handle_training_history(cgi_id)
|
|
}
|
|
|
|
// POST /lineage/:id/sponsor
|
|
if str_eq(action, "sponsor") && str_eq(method, "POST") {
|
|
return handle_record_sponsor(cgi_id, body)
|
|
}
|
|
|
|
// GET /lineage/:id/sponsors
|
|
if str_eq(action, "sponsors") && str_eq(method, "GET") {
|
|
return handle_get_sponsors(cgi_id)
|
|
}
|
|
|
|
// Principal sub-routes: /lineage/:id/principal[/sub-action]
|
|
// action is "principal" or "principal/propose" etc.
|
|
if str_starts_with(action, "principal") {
|
|
let principal_sub: String = if str_eq(action, "principal") {
|
|
""
|
|
} else {
|
|
str_slice(action, 10, str_len(action)) // strip "principal/"
|
|
}
|
|
|
|
// GET /lineage/:id/principal
|
|
if str_eq(principal_sub, "") && str_eq(method, "GET") {
|
|
return handle_get_principal(cgi_id)
|
|
}
|
|
|
|
// DELETE /lineage/:id/principal
|
|
if str_eq(principal_sub, "") && str_eq(method, "DELETE") {
|
|
return handle_dissolve_principal(cgi_id, body)
|
|
}
|
|
|
|
// POST /lineage/:id/principal/propose
|
|
if str_eq(principal_sub, "propose") && str_eq(method, "POST") {
|
|
return handle_propose_principal(cgi_id, body)
|
|
}
|
|
|
|
// POST /lineage/:id/principal/accept
|
|
if str_eq(principal_sub, "accept") && str_eq(method, "POST") {
|
|
return handle_accept_principal(cgi_id, body)
|
|
}
|
|
|
|
// POST /lineage/:id/principal/decline
|
|
if str_eq(principal_sub, "decline") && str_eq(method, "POST") {
|
|
return handle_decline_principal(cgi_id, body)
|
|
}
|
|
}
|
|
|
|
return not_found(path)
|
|
}
|
|
|
|
// ── Startup ───────────────────────────────────────────────────────────────────
|
|
|
|
println(color_bold("Neuron lineage service") + " — v" + lineage_version())
|
|
println(" Port → 7760")
|
|
println(" Engram → " + config("ENGRAM_URL"))
|
|
println(" Network → " + config("NETWORK_URL"))
|
|
println(" Model → " + config("LINEAGE_PROBE_MODEL"))
|
|
println("")
|
|
println(" Routes:")
|
|
println(" POST /lineage/synthesize")
|
|
println(" GET /lineage/:id")
|
|
println(" POST /lineage/:id/consent")
|
|
println(" POST /lineage/:id/validate")
|
|
println(" POST /lineage/:id/train")
|
|
println(" GET /lineage/:id/tier")
|
|
println(" POST /lineage/:id/advance")
|
|
println(" POST /lineage/:id/classify")
|
|
println(" GET /lineage/:id/training-history")
|
|
println(" POST /lineage/:id/sponsor")
|
|
println(" GET /lineage/:id/sponsors")
|
|
println(" POST /lineage/:id/principal/propose")
|
|
println(" POST /lineage/:id/principal/accept")
|
|
println(" POST /lineage/:id/principal/decline")
|
|
println(" GET /lineage/:id/principal")
|
|
println(" DELETE /lineage/:id/principal")
|
|
println("")
|
|
|
|
http_serve(7760)
|