Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Before Delegating to Agents: ADRs and Spec-Driv...

Avatar for smirne smirne
October 10, 2026

Before Delegating to Agents: ADRs and Spec-Driven Development as the Foundation for AI in the Team

SPARklE manages real users' energy data and provides guidance with direct financial impact. In this context human control isn't negotiable. But that doesn't mean giving up on AI: it means building the right foundations before delegating.

The project started as a EU/PNRR-funded research initiative, with four companies involved and features explored freely. When WellD decided to turn it into a product, we found ourselves with a completely different backlog than expected, and an architecture that showed the marks of the research phase's pace.

Two practices helped us rebuild solidity without slowing down development.
First: a formal Architecture Decision Record system where developers and architects discuss a decision with AI, stress-test it with explicit alternatives and trade-offs, and submit it to adversarial review by the team before moving forward: decisions are more solid, shared, and traceable.
Second: Spec-Driven Development, which forces us to refine requirements before writing code and which lets us delegate part of the development to dedicated agents, while keeping human supervision and quality verification on every step.

This isn't a full multi-agent system yet. It's the infrastructure a multi-agent system needs to operate reliably in a domain where mistakes have a real cost.

Key takeaways:

In domains with sensitive data and financial impact, AI gets introduced by building control foundations, not bypassing them.
ADRs with adversarial review make architectural decisions more solid and shared, with or without AI
Spec-Driven Development is the practical prerequisite for delegating development to agents while keeping human oversight

Avatar for smirne

smirne

October 10, 2026

More Decks by smirne

Other Decks in Programming

Transcript

  1. 10 OCTOBER 2026 · MILANO Before Delegating to Agents ADRs

    and Spec-Driven Development as the Foundation for AI in the Team Michele Giacobazzi · CTO, WellD DevFest Milano 2026
  2. AGENDA In 30 minutes • The project • The product

    • The process ◦ ADRs ◦ SDD 2
  3. THE PROJECT SPARklE: a platform for REC • RECs and

    Energy flexibility • Machine learning for forecasts and optimization • 4 companies building together • Demonstration and project deadlines
  4. THE PRODUCT From research to product • • EU /

    PNRR research project: ◦ four companies ◦ strict deadlines ◦ focus on algorithms and advanced features ◦ virtual REC Transition to product: ◦ A different backlog (onboarding, bureaucracy..) ◦ Adding energy efficiency ◦ Real multi-tenancy ◦ Feedback from real users 4
  5. THE PRODUCT The problems • • • New Team Members

    ◦ some choices were hard to understand ◦ some features were half-baked ◦ long onboarding process Scope creep ◦ many new features needed for MVP ◦ advanced features are not yet relevant Real multi tenancy ◦ tested only with a single REC 4
  6. CONTEXT Adding more developers AI to a late project.. •

    AI amplifies what it founds in the project • If devs don’t know Why, nether does AI • Speed moves the bottleneck -> from code to review • The blast radius is real • Debt compounds AI doesn’t untangle a codebase. It makes the tangle faster. 6
  7. ADRs Why we need them? • The why was gone

    • Challenge the decision • Evaluate alternatives • Avoid debate coming back • Document decisions • Agents read files 8
  8. ADRS When? “Software architecture is a set of decisions which

    are both important and hard to change.” — Martin Fowler
  9. ADRS How we write one • Decided in a spec

    session - developer, architect, agents.. • Drafted by an ADR skill - custom format, clarify with questions • Saved as text file - and committed in the repo • Review and amend - the team reviews • Merge and approve - only after verification
  10. ADRS What’s in a ADR • Title - what are

    we deciding • Context - what drove the decision • Status - Proposed → Accepted → Superseded. • Decision - one sentence + implementation points • Alternatives considered - and why we rejected them • • # ADR 001 — Decision title # Status: Proposed # Date: 2026-06-30 # Deciders: [Development Team, architect..] # Context [the facts that lead to the decision in 2-3 sentences] # Decision [We will use/standardize/adopt this to do x] Consequences - positive and negative, # Alternatives considered [A (why not), B] measurable or observable # Consequences [positive · trade-offs · risks] References - specs, related ADRs, tickets # References [Docs, other ADRs..]
  11. ADRS Our ADR system • 22 ADRs since April 2026,

    in the repo: docs/adr/ • Index with status; a numbering collision left visible, not hidden • Decisions build on each other - a security set under a parent policy • Each set ships with a rollout plan and a test gate ADR-003 Identity & Access (parent policy) │ ├── ADR-013 AUTHENTICATION │ every service validates the token ├── ADR-014 EXPOSURE │ public / private / internal tiers │ └── ADR-020 no session to relay └── ADR-015 AUTHORIZATION default-deny RBAC Critical path: 1 → 2 → (4, 5) → 6 each step: a test gate per step docs/adr/README.md
  12. ADRS A real one: ADR-012 (1/2) # ADR-012: Job Scheduling

    & Background Work Strategy Status: Proposed · Date: 2026-06-18 · Deciders: Development Team CONTEXT Background work ran three different ways: JobRunr (in-process, DB-backed) in registry; Spring @Scheduled + ShedLock in stream_gate and economic_engine; Kubernetes CronJobs calling the Python services over HTTP. A proposal was on the table to extract JobRunr into a standalone “scheduling microservice”. Meanwhile a missing @EnableSchedulerLock in economic_engine made the incentive task run twice every night at 03:00. DECISION We will NOT extract JobRunr. It stays embedded in registry; the three mechanisms converge onto two. 1. Keep JobRunr in registry — in-process, type-safe, already multi-replica-safe (DB master election) 2. Storage hygiene — move the jobrunr_* tables out of the domain schema into their own schema 3. Two sanctioned patterns — dynamic / retryable / fan-out work → JobRunr · fixed-schedule work → K8s CronJob + trigger endpoint 4. Retire @Scheduled + ShedLock — inert unless you remember one annotation; it was forgotten once already 5. Execute-once requirement — every job runs once per slot: master election for JobRunr, concurrencyPolicy: Forbid for CronJobs docs/adr/ADR-012-job-scheduling-strategy.md — condensed
  13. ADRS A real one: ADR-012 (2/2) ALTERNATIVES CONSIDERED A. Standalone

    JobRunr microservice (the original proposal) — Rejected. To run the jobs it needs registry’s domain code, repositories and tenant plumbing: it is registry under another name. B. registry web / worker split — Deferred, not rejected. The legitimate form of “JobRunr on its own pod”; justified only if the aggregation job is shown to contend with API traffic. C. JobRunr everywhere (replace ShedLock and the Python CronJobs) — Rejected. Forces the Python services into an HTTP-trigger relationship with a Java-hosted scheduler. CONSEQUENCES ✔ 6 jobrunr tables leave the domain schema — no cross-database migration, no new service ✔ three mechanisms → two, with a one-line selection rule; ShedLock removed from three services ✔ a class of duplicate-execution bugs eliminated by construction — including the live 03:00 one ✘ CronJob tasks run as one HTTP request on one replica: long cleanups must be made async or given generous timeouts ✘ “where is this scheduled?” lives in two places until the migration completes ✘ a few days of migration plus a deprecation window; trigger endpoints must be authenticated — depends on ADR-013 REFERENCES ADR-004 (service-to-service) · ADR-013 (gateway trust boundary) · ADR-014 (exposure tiers) · ADR-007 (CI/CD) · the job classes and manifests · the informal execute-once requirement docs/adr/ADR-012-job-scheduling-strategy.md — condensed
  14. SDD Why specs: the first run • Task to an

    agent: “quantify and reduce the registry pod’s memory” • It re-derived numbers the team already had — and got one negative • It proposed a change that a team decision had already made a no-op • It patched the cluster directly — GitOps reverted it in nine minutes • It read 438,4 as 438 — Italian locale, every derived number silently wrong Nothing was wrong with the model. Everything it got wrong, someone on the team already knew.
  15. SDD What a spec is, for us SPEC what &

    why PLAN how · risks TASKS small · ordered IMPLEMENT agents + QE Code Review
  16. SDD Human supervision, at every step • Interactive definition of

    spec and plan - Human defines context, AI proposes and asks • Verify and approve before coding - start implementation only after the team has reviewed and modified spec and plan • Review the reasoning before the code - when a task hides many small judgment calls, the agent lists them first (item · finding · action · why) and stops for appoval • Verification on the real cluster - every MR is deployed to a single-slot review environment and tested
  17. SDD A real one: a SPARklE feature spec (1/2) spec.md

    — POD → conventional area validation for membership applications id 001 · rigor: production · created 2026-08-03 · approved 2026-08-03 · status: in-progress PROBLEM When a CER administrator approves a membership application, the applicant’s sites are registered with no check that the system knows the conventional area the GSE assigns to each POD. The mismatch surfaces only later, when the site cannot be attributed. The admin has no way to see, before approving, which sites are affected. USER STORY US-1 (one of four) As a CER Administrator, I want to check that every POD in an application belongs to a conventional area that exists in the system, so that I do not approve an application whose sites cannot be attached. AC-1.2 Given at least one site whose area matches no cer_area, when an admin requests validation, then 422 with a failure body — and no state anywhere is modified. AC-1.4 Given a caller without the admin role, then the request is forbidden — and no call is made to the GSE. AC-1.7 the GSE and the registry are queried once per batch of distinct codes, never once per site. Amended 2026-08-04 — GSE truncates large results; the intent (cost proportional to the application) is unchanged. CONSTRAINTS nine decisions taken by the user before the spec, verbatim: one batched GSE call · 422 problem+json per ADR-016 · a GSE outage is a 502 with its own code · the dataset year is configuration. Plus verified GSE behaviour recorded as fact: it returns HTTP 200 even for errors. NON-GOALS persisting the mapping (a separate slice) · any frontend · blocking approval — log-only first, to measure the real failure rate. OPEN QUESTIONS one — answered 2026-08-03, owner named, consequence for this slice written down. specs/001-pod-conventional-area-validation/spec.md — condensed; wording is the original's
  18. SDD A real one: a SPARklE feature spec (2/2) PLAN

    · RISKS seven, numbered, each with a mitigation — R1, R2, R4, R5 later became ADR-021, the standing policy for third-party APIs R1 PODs come from the public onboarding form and are interpolated into the GSE query language → strict allowlist before any call. R2 the shared HTTP interceptor attaches a bearer token to every target — including mappe.gse.it → the GSE client must carry no credential. R5 the yearly dataset silently goes stale → path is configuration; “worth a heartbeat check — noted for the team, not solvable in code here”. Amendment 2026-08-04 a security review found per-site detail in the approval log was site-identifying data written on every approval → ACs amended: counts only, never a POD or a site name in logs. TASKS 15, dependency-ordered; each one: refs AC · deps · files to touch · a verifiable “done when” T1 repository lookup — done when the integration test passes for match, no-match, two rows sharing one substation, and a blank code. T14 fix the defects QE and the security pass found. T15 reconcile approval logging with its amended ACs. EVAL an automated evaluator instructed to be adversarial — three rounds ✘ 65 FAIL → 76 FAIL: “the verdict turned on a single anchor, spec fidelity, and I flagged it as such” ✔ 80 PASS — “exactly on the threshold. That is the honest arithmetic, not a rounding in the feature’s favour.” Tests re-run: 235 + 122 + 587, zero failures ✘ two findings remain open by explicit decision, and are scored as found Amended twice during implementation — both dated, both accepted by a person. Drift became a decision. specs/001-pod-conventional-area-validation/plan.md · tasks.md · eval-report.md — condensed
  19. THE PROJECT Roadmap March 2025 September 2026 Project start REC

    product released December 2025 Research project conclusion and dissemination TODAY January 2027 Energy efficiency
  20. Before delegating Foundations, not bypasses ADRs + adversarial review Specs

    before agents In domains with sensitive data and Architectural decisions become more solid Spec-Driven Development is the practical financial impact, AI gets introduced by and shared, with or without AI. prerequisite for delegating development to building control foundations, not by bypassing them. agents while keeping human oversight.