ontoref/CHANGELOG.md
Jesús Pérez d59644b96f
feat: unified auth model, project onboarding, install pipeline, config management
The full scope across this batch: POST /sessions key→token exchange, SessionStore dual-index with revoke_by_id, CLI Bearer injection (ONTOREF_TOKEN), ontoref setup
  --gen-keys, install scripts, daemon config form roundtrip, ADR-004/005, on+re self-description update (fully-self-described), and landing page refresh.
2026-03-13 20:56:31 +00:00

16 KiB

Changelog

All notable changes to ontoref are documented here. ADRs referenced below live in adrs/ as typed Nickel records.


[Unreleased]

Auth & Session Model (ADR-005)

Unified key-to-session token exchange across all surfaces. All work gated on #[cfg(feature = "ui")].

  • KeyEntry gains label: String (#[serde(default)]) — audit trail for key-based sessions. NCL schema install/resources/schemas/ontoref-project.ncl updated accordingly.
  • verify_keys_list returns Option<KeyMatch { role, label }> instead of Option<Role>.
  • SessionEntry gains id: String — stable public identifier distinct from the bearer token, safe to expose in list responses. Prevents session enumeration by admins.
  • SessionStore gains secondary id_index: DashMap<id, token> for O(1) revoke_by_id.
  • New SessionStore methods: list_for_slug, list_all, revoke_all_for_slug, revoke_by_id(id, acting_slug, acting_role) -> RevokeResult.
  • POST /sessions — key → UUID v4 token exchange. Accepts project keys or daemon admin password (project: "_daemon"). Rate-limited. No authentication required (it is the credential exchange endpoint).
  • GET /sessions?project=slug — list active sessions for a project (viewer+). Without ?project= param requires daemon admin and returns all sessions.
  • DELETE /sessions/{id} — revoke by public id. Project admin: own project only. Daemon admin: any.
  • require_session() helper: validates UUID v4 Bearer → SessionEntry, error boxed (Box<Response>) to satisfy clippy::result_large_err.
  • check_primary_auth fast-path: UUID v4 bearer → session lookup (O(1)) before argon2 fallback (~100ms).
  • project_update_keys (PUT /projects/{slug}/keys) now calls sessions.revoke_all_for_slug in addition to actor deregistration. All in-flight UI sessions for the rotated project are immediately invalidated.
  • Daemon admin: ONTOREF_ADMIN_TOKEN_FILE (preferred — hash not visible in ps aux) or ONTOREF_ADMIN_TOKEN. Sessions use virtual slug "_daemon".
  • manage_login_page / manage_login_submit / manage_logout handlers for /ui/manage/login and /ui/manage/logout.
  • AdminGuard redirects to /ui/manage/login when daemon_admin_hash is set.

CLI Bearer Token

  • bearer-args exported from reflection/modules/store.nu: returns ["-H" "Authorization: Bearer $token"] when ONTOREF_TOKEN is set, [] otherwise.
  • http-get, http-post-json, http-delete (new) in store.nu use ...$auth — Bearer injected transparently, no behavior change when ONTOREF_TOKEN is unset.
  • notify-daemon-project-add and notify-daemon-project-remove in reflection/bin/ontoref.nu use bearer-args.

Project Setup & Onboarding

  • ontoref setup is now the primary onboarding command (replaces manual cp templates/ pattern).
  • --kind <K> flag: Service (default) | Library | DevWorkspace | PublishedCrate | AgentResource | Mixed.
  • --parent <path> flag: generates manifest with implementation layer + <slug>-framework layer and <slug>-browse op mode for implementation children.
  • Logo auto-detection: setup scans assets/ for <slug>-logo.svg, <slug>.svg, logo.svg (and .png variants); inserts ui.logo into generated config.ncl when found.
  • --gen-keys ["admin:label" "viewer:label"] flag: idempotent bootstrap — skips if role = already present in project.ncl. Hashes via ontoref-daemon.bin --hash-password; prints passwords once to stdout.
  • All mkdir calls in setup guarded by if not (path | path exists).

Self-Description — on+re Update

.ontology/core.ncl — 3 new Practice nodes, updated ontoref-daemon description and artifact_paths:

Node Pole Description
unified-auth-model Yang Key→session token exchange; session.id ≠ bearer; revoke on key rotation
project-onboarding Yang ontoref setup — idempotent scaffold, --kind, --parent, --gen-keys

ontoref-daemon node updated: auth/session management added to description and artifact_paths (session.rs, auth.rs, login.rs).

New edges: unified-auth-model → ontoref-daemon, unified-auth-model → no-enforcement (Contradicts/Low — auth is opt-in), ontoref-daemon → unified-auth-model (Contains), project-onboarding → unified-auth-model (DependsOn), project-onboarding → adopt-ontoref-tooling (Complements), project-onboarding → daemon-config-management (DependsOn).

.ontology/state.nclself-description-coverage transitions to current_state = "fully-self-described". Blocker resolved: reflection/backlog.ncl created, ADR-005 recorded.

reflection/backlog.ncl — created with 6 items: bl-001 (ontoref.dev), bl-002 (first external project), bl-003 (ontoref keys CLI), bl-004 (session UI views), bl-005 (Syntaxis migration), bl-006 (ADR-001 acceptance).

Previous state: 4 axioms, 2 tensions, 13 practices. Current: 4 axioms, 2 tensions, 15 practices.

Protocol

  • ADR-004 accepted: NCL pipe bootstrap pattern — nickel export config.ncl | ontoref-daemon.bin --config-stdin. Stages: Nickel evaluation → optional SOPS/Vault merge → binary via stdin. (adr-004)
  • ADR-005 accepted: unified key-to-session auth model across CLI, UI, and MCP. Opaque UUID v4 tokens, session.id ≠ bearer, revocation on key rotation, daemon admin via _daemon slug. (adr-005)

Install Infrastructure

  • install/ directory reorganized: binaries, bootstrapper, global CLI, resources, and validation scripts co-located.
  • Binary installed as ontoref-daemon.bin; public entrypoint bootstrapper installed as ontoref-daemon. Users never call .bin directly.
  • install/ontoref-daemon-boot (renamed from ontoref-daemon-start) — NCL pipe bootstrapper implementing ADR-004. Stages: nickel export config.ncl → optional SOPS/Vault secret merge → ontoref-daemon.bin --config-stdin. Supports --dry-run, --sops, --vault.
  • install/ontoref-daemon-boot sets NICKEL_IMPORT_PATH (config dir + platform data dir schemas) and NATS_STREAMS_CONFIG (default ~/.config/ontoref/streams.json) before launching the binary.
  • install/install.nu — installs binary, bootstrapper, global ontoref CLI (ONTOREF_ROOT baked in at install time), UI assets, config skeleton, and global NATS topology. Hash-checked — unchanged files are not overwritten.
  • install/config-setup.nu — standalone validation script: nickel typecheck + nickel export, path existence checks, DB and NATS liveness probes (nc -z -w2).
  • install/check-config-sync.nu — CI guard asserting that every nickel_path-bearing field in reflection/forms/config.ncl has a matching {{ name }} reference in reflection/forms/config.ncl.j2, and vice versa. Wired into just ci-lint and just ci-full.

Config Management

  • install/resources/config.ncl — default global config skeleton with full Nickel contracts (Port, LogLevel, Rotation, Actor, Severity). Covers: daemon, db, nats_events, log, cache, ui, mode_run, actor_init, quick_actions, nickel_import_paths.
  • install/resources/streams.json — global default NATS JetStream topology: ECOSYSTEM stream (ecosystem.>, 30-day retention), no project-specific consumers. Installed to ~/.config/ontoref/streams.json.
  • nats/streams.json — ontoref project-local topology with daemon-ontoref and cli-notifications consumers on ECOSYSTEM stream.
  • reflection/forms/config.ncl + reflection/forms/config.ncl.j2 — typedialog roundtrip for browser-based config editing (ontoref config-edit). Form populates fields from existing config via nickel_path; Tera template reconstructs full NCL with all contracts on save.
  • reflection/nulib/bootstrap.nu — Nu bootstrapper helper updated: nats-streams-config function resolves NATS_STREAMS_CONFIG default; env var passed to daemon process via with-env.
  • Daemon nats.rs: empty streams_config string → None, activating TopologyConfig::load fallback to NATS_STREAMS_CONFIG env var. Projects with a local nats/streams.json set streams_config explicitly in their config.

Daemon Fixes

  • --config-stdin now exclusively skips .ontoref/config.ncl — project config is never loaded when stdin config is active. Previously both paths could run.
  • DB connection (stratum-db) only established when db.enabled = true in config. Previously connected regardless of enabled flag.
  • NATS connection (platform-nats) only established when nats_events.enabled = true. "Connecting to NATS..." log moved after the enabled check.
  • NatsPublisher::connect signature changed from config_path: &PathBuf (re-read file) to config: Option<&serde_json::Value> (already-loaded JSON). Eliminates double file read and ensures NATS uses the same config source as the rest of the daemon.
  • load_config_overrides returns (Option<String>, Option<serde_json::Value>) — nickel import path and parsed config JSON returned together. apply_stdin_config returns serde_json::Value directly.

Self-Description — on+re Update

.ontology/core.ncl — 1 new Practice node, updated ontoref-daemon description and artifact_paths:

Node Pole Description
daemon-config-management Yang Install + config form/template roundtrip, CI guard, global NATS topology, config-setup validation

New edges: daemon-config-management → ontoref-daemon (DependsOn), daemon-config-management → adopt-ontoref-tooling (Complements).

.ontology/state.ncloperational-mode dimension description updated to reference ADR-004 bootstrap and NATS_STREAMS_CONFIG mechanism. protocol-maturity blocker updated to reflect install pipeline completion.

.ontology/manifest.ncltooling layer paths updated to include install/ and nats/.

Previous state: 4 axioms, 2 tensions, 12 practices. Current: 4 axioms, 2 tensions, 13 practices.

Protocol

  • ADR-001 accepted: ontoref extracted as a standalone protocol project, independent of stratumiops versioning and release cycle. Consumer projects adopt via scripts/ontoref wrapper + .ontoref/config.ncl. (adr-001)
  • ADR-002 accepted: ontoref-daemon introduced as optional persistent daemon for NCL export caching (keyed by path+mtime), actor registry (developer/agent/CI), and notification barrier (pre-commit hook, fail-open). Supersedes stratumiops ADR-007. (adr-002)
  • ADR-003 accepted: Q&A and accumulated operational knowledge persist to reflection/qa.ncl — typed NCL, git-versioned, accessible via MCP tools and HTTP endpoints. localStorage eliminated. Q&A entries survive session boundaries and are queryable by any actor. (adr-003)

Crates

  • ontoref-ontology: Rust crate for loading .ontology/*.ncl as typed structs (Core, Gate, State). Zero stratumiops dependencies.
  • ontoref-reflection: Rust crate for loading, validating, and executing Reflection modes as NCL DAG contracts. Optional nats feature (path dep: platform-nats).
  • ontoref-daemon: Rust crate providing HTTP API (axum), DashMap-backed NCL export cache, notify-based file watcher, and actor registry. Optional db feature (path dep: stratum-db) and nats feature (path dep: platform-nats).

Daemon — Q&A NCL Persistence (crates/ontoref-daemon/src/ui/qa_ncl.rs)

Line-level NCL surgery for reflection/qa.ncl — same pattern as backlog_ncl.rs. No AST parsing, no nickel-lang-core dependency.

  • add_entry — appends a typed QaEntry block before ], array close; generates sequential qa-NNN ids
  • update_entry — in-place field mutation via bidirectional scan (question + answer fields)
  • remove_entry — removes the full block by id using backward scan for { and forward scan for },

HTTP endpoints (all under #[cfg(feature = "ui")] except read-only GET):

  • GET /qa-json — export all Q&A entries as JSON (read-only, always enabled)
  • POST /qa/add — append new entry; returns generated id
  • POST /qa/delete — remove entry by id; invalidates NCL cache
  • POST /qa/update — mutate question + answer fields by id; invalidates NCL cache
  • GET /actions/run / POST /actions/run — execute a quick action by id; spawns ./ontoref <mode>

Server-side hydration: qa.html receives entries as Tera context variable, embeds SERVER_ENTRIES JSON literal in the page <script> — no fetch round-trip on load.

Daemon — MCP Tools (crates/ontoref-daemon/src/mcp/mod.rs)

Four new MCP tools exposed to AI agents:

Tool Description
ontoref_qa_list List Q&A entries with optional filter substring match. Never triggers ontology sync.
ontoref_qa_add Append a new Q&A entry to reflection/qa.ncl; invalidates NCL cache.
ontoref_action_list List all quick actions from .ontoref/config.ncl export.
ontoref_action_add Create a new reflection mode at reflection/modes/<id>.ncl and register it as a quick action.

Constraint: ontoref_qa_list and ontoref_qa_add never trigger apply steps or modify .ontology/ files (enforced by ADR-003).

Daemon — Passive Drift Observation (crates/ontoref-daemon/src/ui/drift_watcher.rs)

Background observer bridging Yang code artifacts with Yin ontology declarations:

  • Watches crates/, .ontology/, adrs/, reflection/modes/ via notify file watcher
  • 15-second debounce window before triggering scan
  • Spawns ./ontoref sync scan && ./ontoref sync diff as read-only subprocesses
  • Parses stdout for MISSING / STALE / DRIFT / BROKEN markers
  • Emits ontology_drift notification via push_custom when any drift is found
  • Never applies changes automatically — apply remains a deliberate human or agent act

Started from main.rs under #[cfg(feature = "ui")]; failure to start is non-fatal (logged as warning).

Tooling

  • reflection/modules/: 16 Nushell operational modules (adr.nu, backlog.nu, coder.nu, describe.nu, sync.nu, etc.)
  • reflection/modes/: 10 NCL DAG operational modes including adopt_ontoref, sync-ontology, coder-workflow, create-pr
  • reflection/forms/: 7 interactive NCL forms for ADR lifecycle, backlog, and adoption
  • templates/: Consumer-facing adoption templates (ontoref-config.ncl, ontology/, scripts-ontoref)
  • ./ontoref: Bash entry point with actor auto-detection, advisory file locking, and Nushell version guard (>= 0.110.0)

Self-Description — on+re Update

.ontology/core.ncl updated with 3 new Practice nodes and 9 new edges:

Node Pole Description
qa-knowledge-store Yin Q&A entries as typed NCL — accumulated knowledge queryable by any actor
quick-actions Yang Runnable shortcuts over reflection modes; configured in .ontoref/config.ncl
drift-observation Spiral Passive bridge between Yang code artifacts and Yin ontology declarations

New edges: qa-knowledge-store → dag-formalized, qa-knowledge-store → coder-process-memory, ontoref-daemon → qa-knowledge-store, quick-actions → reflection-modes, quick-actions → ontoref-daemon, describe-query-layer → quick-actions, drift-observation → ontoref-daemon, drift-observation → ontology-vs-reflection, drift-observation → reflection-modes.

Previous state: 4 axioms, 2 tensions, 9 practices. Current: 4 axioms, 2 tensions, 12 practices.

reflection/schemas/qa.nclQaStore and QaEntry types (id, question, answer, actor, created_at, tags, related, verified). reflection/qa.ncl — typed store file, conforms to QaStore contract, Nickel typecheck must pass.


ontoref uses its own ADR system to track decisions. Architectural rationale lives in adrs/, not in this file.