Skip to content

[feat] App-type capability profiles: required-feature gates + best-practice playbooks per application archetype #79

Description

@wimaan3

Problem / motivation

borromeanRings today gates how well code is written (build, lint, types, tests, security, layout) and what engineering surround exists ([hygiene].requires), and it adjusts checks per language (ADR-0015). What it does not yet gate is whether an application has the capabilities an app of its kind must have to be correct, safe, and complete.

An AI agent asked to "build a web API" will produce something that passes the quality gate (clean, typed, tested) yet is missing things that are non-negotiable for that app type — input validation at the boundary, authN/authZ, rate limiting, non-leaking error handling, a health endpoint, secrets from the environment. The agent doesn't know what "complete" means for this archetype, and nothing fails closed when those are absent. That's a correctness and security gap — exactly the kind of thing a meta-harness should make deterministic instead of leaving to agent taste.

Proposed change

Add an application-archetype dimension to the spine. A project declares its kind:

[project]
language = "python"
kind = "web-api"   # selects a capability profile (new)

Each capability profile (web-api, web-app, cli, library, worker, data-pipeline, embedded/firmware, …) declares a set of required capabilities, each with two halves:

  1. A fail-closed check (checks/profiles/<kind>/*) asserting the capability is present and wired — producing a receipt like every other check.
  2. An agent-facing playbook — the best-practice options/libraries for that capability and how to implement it well with an AI agent (loaded only when relevant, the way cs130-se routes by task).

Worked example — web-api profile (illustrative)

Required capability Deterministic check (fail-closed) Playbook covers
Input validation at boundaries a declared validation layer is present + exercised by a test schema validation libs, where to validate, fail-fast
AuthN/AuthZ declared auth mechanism present + a test asserting unauthorized access is rejected session vs token vs OAuth, least-privilege
Rate limiting declared limiter wired on public endpoints algorithms, per-key limits, 429 semantics
Non-leaking error handling error handler present + test asserting no stack/secret in responses structured errors, safe messages
Health/readiness endpoint endpoint exists + responds liveness vs readiness
Secrets management no hardcoded secrets (extends 50_security) + env/secret-manager usage declared env vars, secret managers, rotation

Worked example — embedded profile (illustrative; shows the range)

Required capability Deterministic check (fail-closed) Playbook covers
Deterministic memory no dynamic allocation after init; no malloc/heap in ISRs; bounded stack usage static/pool allocation, stack-depth analysis, fragmentation avoidance
GPIO discipline every pin explicitly configured before use; init/deinit paired; no floating inputs pull-up/down, debouncing, HAL abstraction, idempotent init
ISR safety shared vars volatile; ISRs short + non-blocking; critical sections guard shared state reentrancy, defer-to-main-loop, lock-free patterns
Watchdog & timing watchdog configured and kicked; real-time/WCET budget documented watchdog patterns, RTOS priorities, priority-inversion avoidance
Fail-safe state brown-out detection; safe default outputs on reset/fault safe-state design, hardware fault handling
Coding-standard compliance MISRA C / static analysis (cppcheck, clang-tidy) passes; no UB; no exceptions/RTTI where banned MISRA rationale, UB avoidance, freestanding C/C++
Off-target testability hardware-abstraction layer present so logic is testable without hardware HAL seams, host/simulation tests, HIL

The determinism question (the crux)

"Does this API have good rate limiting?" can't be fully verified statically — so profiles use declare-and-verify, the same model as [hygiene].requires and the coverage ratchet: the project declares which mechanism satisfies each required capability; the check verifies the declared mechanism is present and backed by a test/config artifact, failing closed if a required capability is undeclared or unevidenced. borromeanRings makes the requirement deterministic even where fully-automatic quality detection isn't possible; the playbook raises implementation quality.

Enforcement richness is archetype-dependent. Some profiles are far more statically checkable than others: embedded practices like "no heap in ISRs", volatile on shared state, and MISRA compliance are real static-analysis gates, whereas "good rate limiting" leans on declare-and-verify. The profile model accommodates both — a check is as strict as its archetype permits, falling back to declare-and-verify only where automatic detection is undecidable.

Flexibility / evolvability (first-class requirement)

Capability profiles must be evolvable; a frozen checklist becomes wrong as the frontier moves:

  • Profiles are declarative, versioned data — not hardcoded check logic. Adding, retiring, or changing a required capability is a data/config edit, not a rewrite. Each profile carries a version.
  • Decouple the durable "what" from the volatile "how." The capability ("validate input at boundaries", "no heap in ISRs") changes slowly; the playbook ("use library X / algorithm Y") changes fast. Keep them in separate layers so best-practice churn lives in the playbook, not the gate.
  • Per-project override + pinning. A project can extend, relax (with recorded rationale), or pin a profile version for reproducibility — consistent with the opt-in config spine (ADR-0010). A changed best practice never silently breaks a passing build; upgrades are explicit and reviewable.
  • Lifecycle, not silent edits. Capabilities graduate advisory → required (or retire) as consensus shifts; every change is recorded (ADR trail / changelog).
  • Evidence-gated changes. Profile updates flow through the frontier-tracking process ([feat] Frontier-tracking: distill authoritative agent-engineering sources + experiment to extend them #80): experiment → validate → update via gated PR, with provenance. No vibes-based edits.

This profile system is the consumer of the frontier-tracking process: that process discovers and validates how best practices change; this system is where validated changes land — as versioned profile/playbook updates rather than ad-hoc rewrites.

Scope / non-goals

  • Not a scaffolding/codegen tool: borromeanRings does not implement features or generate the app. The agent builds; borromeanRings declares the required set, gates completeness, and routes to best practices. (Manifesto: stay narrow.)
  • Profiles are opt-in and declared (empty/absent kind ⇒ feature off), consistent with ADR-0010.
  • Profiles ship conservative, evidence-based capability lists; declared policy, tunable per project.

Alternatives considered

  • One global checklist for all apps — rejected: capability needs are archetype-specific; a CLI doesn't need rate limiting, an MCU doesn't allocate on the heap.
  • Pure static detection as the sole mechanism — rejected: undecidable in general; declare-and-verify is honest and fail-closed.
  • Playbooks only (guidance, no gate) — rejected: borromeanRings turns standards into gates, not suggestions.

Fit with the roadmap

Post-v0 epic (spans many checks + playbooks + profile selection). Land after current increments are proven (Lean: don't build deferred components early). Phasing: (1) profile selection in the spine + one archetype (web-api) with 2–3 highest-value capabilities; (2) the playbook/skill-routing half; (3) more archetypes once proven.

Open questions

  • Archetype taxonomy + granularity — e.g., does embedded split into bare-metal / RTOS / embedded-Linux (very different memory and concurrency rules), and how do sub-types inherit a base profile?
  • Do playbooks live as skills (skills/) or routed reference docs (like cs130-se)?
  • How does a profile compose with language (kind × language matrix)?
  • Per-capability severity — all fail-closed, or some advisory at first?
  • Versioning & upgrade policy — pin (reproducible, opt-in upgrades) vs float (always-current, may newly fail). Likely pin-by-default with explicit upgrades.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestepicTracking issue spanning multiple work itemsharness-featureA borromeo meta-harness capability

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions