End-to-end walkthrough: Login Flow для AcmeCorp

Один полный цикл RENAR от подписанного ТЗ до accepted release. Пример — внутренний инструмент с регистрацией через корпоративный email и 2FA. Цель — показать все этапы на одном среднем по размеру проекте.

Контекст: AcmeCorp, ~1 спринт работы команды, стек Next.js + FastAPI + PostgreSQL. RENAR-зрелость уровня RENAR-3+ (полный ADAPT + TC + adversarial). Substrate в примерах — git + tausik runtime; substrate-agnostic core применим на любом substrate с capabilities V1-V6.

Предпосылки: 00-quickstart, core/renar-core, reference/01-glossary.


Phase 0 — Elicitation

До подписания ТЗ. AI-агент проводит 2-3 интервью с stakeholder’ами (Sales Director, IT Manager) и собирает контекст в structured form.

Артефакты Phase 0 (informative, не нормативные для RENAR Core):

acmecorp-login.req/
  elicitation/
    domain-context.md             # домен и его особенности
    sales-director.yaml           # transcripts + structured findings
    it-manager.yaml
    findings-clustered.md         # сгруппированные находки
    critic-review.md              # adversarial review draft требований
    multi-model-diff.md           # разногласия двух моделей

Phase 0 не нормирован в Core (это область elicitation methodology, см. research/11-elicitation-workflow.md).


Phase 1 — TZ import

1.1 Подписанный ТЗ

После итераций elicitation клиент подписывает TZ-2026-042:

# TZ-2026-042 — Login Flow для AcmeCorp Internal Tool
Дата подписания: 2026-05-03
Стороны: AcmeCorp + Kibertum

## §1. Цели
Сократить время входа сотрудников AcmeCorp в инструмент до <2 минут
от первого захода до полного доступа.

## §2. Функциональные требования

### ФТ-001. Регистрация по корпоративному email
Сотрудник регистрируется через email из домена @acmecorp.com.
Email вне домена — отказ с пояснением.

### ФТ-002. Двухфакторная аутентификация (TOTP)
После регистрации обязательная настройка 2FA через TOTP.

### ФТ-003. Восстановление доступа через корпоративный admin
При потере 2FA устройства — recovery через ticket в IT support.

## §3. Нефункциональные требования

### НФТ-001. Производительность
Login <2 секунд (p95).

### НФТ-002. Безопасность
- bcrypt cost-factor ≥ 12.
- Логи входов хранятся 1 год.
- Блокировка после 5 неудачных попыток за 15 минут.

### НФТ-003. Юрисдикция
Все данные в РФ (гос-контракты).

ТЗ подписан → immutable. Любые правки идут через ADAPT (см. Phase 2) или delta-TZ (см. Phase 8).

1.2 Substrate-native импорт

Пример команды для git+tausik substrate:

$ tausik req import-tz --order-id 042 --type initial \
    --signed-date 2026-05-03 \
    --source ./tz-input/TZ-2026-042.md

✓ Created acmecorp-login.req/tz/TZ-2026-042.md
✓ Branch created: feat/TZ-2026-042-initial
✓ AI-provenance recorded: import by tausik-import@v1.4

Для других substrate — эквивалентная operation импорта immutable документа с pin на substrate-native revision.


Phase 2 — ADAPT (двусторонняя интерпретация)

2.1 AI генерирует draft ADAPT

$ tausik req adapt-from-tz --tz TZ-2026-042

[claude-opus-4-7] Reading TZ...
[claude-opus-4-7] Generating Forward sections... 3 (по §2 ФТ-001/002/003 + §3 НФТ).
[claude-opus-4-7] Generating Backward findings... 6 candidates.
[claude-opus-4-7] Generated draft ADAPT-001.

Cost: 14,200 input + 3,800 output tokens
Time: 28s

2.2 Adversarial review backward записей

$ tausik req adversarial-review --adapt ADAPT-001

[gpt-4-turbo:critic] Reviewing backward findings...

[HIGH] B-001 (gap) "lost 2FA device recovery" дублирует ФТ-003 — это не gap,
       а уточнение workflow. Reclassify как hidden-assumption.
[HIGH] Missed backward: ФТ-001 не описывает case-sensitivity email — gap.
[MEDIUM] B-004 (terminology) "сотрудник" — нужно определить через User.role.
[MEDIUM] B-006 (feasibility) "блокировка после 5 попыток" — за 15 минут на
       одно IP, на один email, или на одну сессию? Уточнить с клиентом.

→ 4 findings: 2 high (reclassify, missed), 2 medium (clarification)
→ Block adapt-approve until resolved.

2.3 Iterative resolution

Архитектор корректирует Forward и Backward, AI re-генерирует. После 2 циклов adversarial:

  • 7 backward записей (B-001..B-007).
  • Все либо resolved (после ответа клиента), либо reclassified.
  • Forward охватывает §2 + §3 ТЗ полностью.

2.4 Approved ADAPT

---
id: ADAPT-001
title: "Адаптация TZ-2026-042 — Login Flow AcmeCorp"
type: ADAPT
source-tz:
  id: TZ-2026-042
  signed-date: "2026-05-03"
  signed-by-client: "AcmeCorp PM"
status: approved
approval:
  client-signature:
    signed-by: "Иванова А.А."
    role: "Product Lead"
    organization: "AcmeCorp"
    signed-at: "2026-05-04T11:30:00Z"
  architect-signature:
    signed-by: "Петров П.П."
    role: architect
    signed-at: "2026-05-04T12:00:00Z"
generates-requirements: [BR-01, BR-02, SR-01, SR-02, SR-03, SR-04, SR-05, SR-06, SR-07]
generates-specs: [SPEC-UI-01, SPEC-API-01, SPEC-DATA-01, SPEC-SEC-01]
open-questions-count: 0
resolved-questions-count: 7
ai-provenance:
  generated-by: "anthropic-claude-opus-4-7@2026-05-04"
  prompt-template: "prompts/adapt-from-tz.md@v2.1"
  human-edits: true
---

После approval ADAPT-001 — immutable.


Phase 3 — Декомпозиция в BR / SR / SPEC

3.1 Команда

$ tausik req decompose --adapt ADAPT-001

[claude-opus-4-7] Reading approved ADAPT...
[claude-opus-4-7] Generating BR candidates from Forward §1 (бизнес-цели)... 2 found.
[claude-opus-4-7] Generating SR candidates from Forward §2-§3... 7 found.
[claude-opus-4-7] Generating SPEC candidates (parallel axis)... 4 found.
[claude-opus-4-7] Generated draft artifacts.

3.2 Adversarial review артефактов

[gpt-4-turbo:critic] Reviewing draft BRs, SRs and SPECs...

[HIGH] BR-01 stakeholder поле пустое — кто owner business goal?
[HIGH] SR-05 говорит "bcrypt cost-factor 12" — это deployment detail,
       должно быть в SPEC-SEC-01, не в SR.
[MEDIUM] НФТ-003 (юрисдикция) не отражено в data-classification SR-01.
[MEDIUM] SPEC-UI-01 не имеет accessibility-level — WCAG-AA минимум для
       корпоративного инструмента.

→ 4 findings → fix → re-generate.

3.3 Финальный набор артефактов

acmecorp-login.req/
├── br/
│   ├── BR-01-self-service-registration.md
│   └── BR-02-secure-mfa.md
├── sr/
│   ├── SR-01-email-domain-validation.md       (ФТ-001)
│   ├── SR-02-totp-enrollment.md               (ФТ-002 setup)
│   ├── SR-03-totp-verification.md             (ФТ-002 verify)
│   ├── SR-04-password-recovery-via-admin.md   (ФТ-003)
│   ├── SR-05-rate-limiting-failed-logins.md   (НФТ-002)
│   ├── SR-06-audit-logging.md                 (НФТ-002 audit)
│   └── SR-07-data-residency-ru.md             (НФТ-003)
├── specs/
│   ├── ui/SPEC-UI-01-login-flow.md
│   ├── api/SPEC-API-01-auth.md
│   ├── data/SPEC-DATA-01-user-model.md
│   └── sec/SPEC-SEC-01-auth-policy.md
└── tz/
    └── TZ-2026-042.md

3.4 Пример: SR-01 frontmatter

---
id: SR-01
title: "Валидация домена email при регистрации"
type: SR
status: approved
parent:
  id: BR-01
source:
  adapt: "ADAPT-001"
  adapt-section: "Forward §2.1"
  tz-section: "§2 ФТ-001"
constrained-by:
  - "SPEC-API-01"     # endpoint POST /auth/register
  - "SPEC-DATA-01"    # схема User
  - "SPEC-SEC-01"     # auth policy
data-classification:
  contains-pii: true
  data-residency: ["RU"]
  retention-days: 365
compliance:
  - { standard: "ФЗ-152", article: "ст.13.1" }
ai-provenance:
  generated-by: "anthropic-claude-opus-4-7@2026-05-04"
  prompt-template: "prompts/decompose-adapt.md@v2.1"
  context-tokens: 12450
  output-tokens: 320
  human-edits: true
---

## Описание

Регистрация разрешена только если email принадлежит домену
`@acmecorp.com`. Остальные домены отклоняются с понятным пояснением.

## Поведение

- email НЕ из `@acmecorp.com` → 422 с body
  `{"error":"email-domain-not-allowed", "allowed-domain":"acmecorp.com"}`.
  [ADAPT-001 §2.1 Forward; TZ-2026-042 §2 ФТ-001]
- email из `@acmecorp.com` → стандартная регистрация (см. SPEC-API-01).
- whitelist хранится в SPEC-SEC-01.allowed-domains, расширяется без релиза.
- сравнение домена — case-insensitive (ADAPT-001 §2.1 Forward).

## Ограничения

- `*.acmecorp.com` subdomain — отдельное решение архитектора (не входит).

3.5 SPEC-API-01 (фрагмент)

---
id: SPEC-API-01
title: "REST API аутентификации"
type: SPEC-API
status: approved
source:
  adapt: "ADAPT-001"
  adapt-section: "Forward §2"
api-style: rest
api-version: "v1.0.0"
versioning-strategy: url-path
authentication: bearer-jwt
rate-limits:
  - { endpoint: "POST /auth/login", limit: "5/15min/ip+email" }
contract-file:
  format: openapi-3.1
  location: "contracts/auth-api.yaml"
depends-on:
  - "SPEC-DATA-01"
  - "SPEC-SEC-01"
---

## Endpoints

### POST /auth/register
- body: `{"email": "<corp-email>", "password": "<strong>"}`
- 201 → `{"user_id": "<uuid>", "verified": false, "totp_setup": false}`
- 422 → invalid email или weak password
- 409 → email уже зарегистрирован

### POST /auth/login
- body: `{"email": "<corp-email>", "password": "<password>", "totp": "<6digits>"}`
- 200 → `{"access_token": "<jwt>", "expires_in": 3600}`
- 401 → invalid credentials
- 429 → rate limit (5/15min)

### POST /auth/totp-setup
- ... (см. SR-02)

## Error model
Единая структура: `{"error": "<code>", "details": {...}}`.

Phase 4 — TC generation (pos/neg pair)

4.1 Команда

$ tausik tc generate --requirement SR-01

[claude-opus-4-7] Analyzing SR-01...
[claude-opus-4-7] Identified 2 testable assertions:
  - allowed domain → 201
  - disallowed domain → 422
[claude-opus-4-7] Generating positive TCs... 2.
[claude-opus-4-7] Generating negative TCs... 2.

Generated:
  tests/TC-001-sr01-allowed-domain-pos.md
  tests/TC-002-sr01-allowed-domain-neg.md   (case mismatch)
  tests/TC-003-sr01-disallowed-domain-pos.md (правильно отказывает)
  tests/TC-004-sr01-disallowed-domain-neg.md (плохо отказывает)

Pos/neg парность из Правила 4 RENAR Core: для каждого assertion’а в SR — 1 pos + 1 neg TC.

4.2 Пример TC-001 (позитивный)

---
id: TC-001
title: "Регистрация с разрешённым доменом — happy path"
type: system
status: ready
verifies:
  - id: SR-01
    requirement-version: "1.0"
negative: false
automation:
  status: automated
  location: "tests/auth/test_registration.py::test_allowed_domain_succeeds"
  runner: pytest
---

## Given
- БД пуста; email alice@acmecorp.com не зарегистрирован.

## When
POST /auth/register {email: "alice@acmecorp.com", password: "ValidPass123!"}

## Then (Pass)
- status 201
- response body содержит {"user_id": "<uuid>", "verified": false, "totp_setup": false}
- в БД создан User(email="alice@acmecorp.com", verified=false, totp_setup=false)
- verification email отправлен (mock SES получил вызов с template_id)

## Fail criteria
- status ≠ 201
- response body содержит plaintext password или его hash
- User в БД с другим email (case mismatch)
- email верификации не отправлен
- в логах plaintext password

## Not in scope
- TOTP setup → TC-005 (verifies SR-02)
- Rate limiting → TC-009 (verifies SR-05)

4.3 Пример TC-004 (негативный)

---
id: TC-004
title: "Регистрация с неразрешённым доменом — отказ с пояснением"
type: system
status: ready
verifies:
  - id: SR-01
    requirement-version: "1.0"
negative: true
automation:
  status: automated
  location: "tests/auth/test_registration.py::test_disallowed_domain_rejected"
  runner: pytest
---

## Given
- email "bob@gmail.com" (вне whitelist).

## When
POST /auth/register {email: "bob@gmail.com", password: "ValidPass123!"}

## Then (Pass)
- status 422
- response body == {"error": "email-domain-not-allowed", "allowed-domain": "acmecorp.com"}
- User в БД НЕ создан
- email НЕ отправлен
- в логах audit-запись о rejected attempt (для SR-06)

## Fail criteria
- status ≠ 422
- User создан в БД
- email отправлен (security leak)
- audit-запись отсутствует

Phase 5 — QG-1 approval

5.1 Все обязательные TC сгенерированы

После генерации TC для всех 7 SR — суммарно 26 TC (pos+neg + extra negatives для SR-05, SR-06).

5.2 QG-1 promote BR-01 → approved

$ tausik req promote --to approved --requirement BR-01

QG-1 conditions:
  ✓ source.adapt = ADAPT-001 (status: approved)
  ✓ All children SR в status >= draft
  ✓ adversarial-review passed (cycle 2 of 2)
  ✓ TCs generated для всех priority=must children
  ✓ pos/neg pair coverage = 100% (26/26 TC паренные)
  ✓ All assertions имеют citations к ADAPT-001

[architect approves]
✓ BR-01 status: draft → approved
✓ All children SR cascade: draft → approved
✓ All TCs: draft → ready

Phase 6 — Реализация

6.1 Создание задач (TR)

$ tausik req sync-tasks --substrate tausik

Создаю TR:
  TR-101: Implement domain validation (SR-01) — assignee: @backend-dev
  TR-102: Implement registration form (SPEC-UI-01) — assignee: @frontend-dev
  TR-103: Implement TOTP enrollment (SR-02) — assignee: @backend-dev
  ... 7 TR total

Каждая TR:
  - parent.id: <SR>
  - implements-spec: [<relevant SPEC>]
  - QG-0 готов (Goal+AC из SR.поведение + SPEC contracts)

6.2 Разработчик берёт TR-101

$ tausik task start TR-101

[QG-0] Verifying task readiness...
  ✓ Goal exists (from SR-01)
  ✓ AC list (4 items из SR-01.поведение)
  ✓ parent.id: SR-01 (resolves; status=approved)
  ✓ implements-spec: [SPEC-API-01, SPEC-SEC-01]
  ✓ Negative scenario in AC: yes (case-mismatch test)
  ✓ Threat surface: low (input validation)

Task ready. Starting work session.

6.3 Реализация (фрагмент)

# acmecorp-login.src/src/auth/registration.py
from fastapi import HTTPException
from config import settings   # allowed-domains из SPEC-SEC-01

def validate_email_domain(email: str) -> None:
    domain = email.split("@", 1)[-1].lower()
    if domain not in settings.AUTH_ALLOWED_DOMAINS:
        raise HTTPException(
            status_code=422,
            detail={
                "error": "email-domain-not-allowed",
                "allowed-domain": settings.AUTH_ALLOWED_DOMAINS[0],
            },
        )
# acmecorp-login.src/tests/auth/test_registration.py
def test_allowed_domain_succeeds(client, db, mock_ses):
    r = client.post("/auth/register",
        json={"email": "alice@acmecorp.com", "password": "ValidPass123!"})
    assert r.status_code == 201
    assert "user_id" in r.json()
    user = db.query(User).filter_by(email="alice@acmecorp.com").one()
    assert user.verified is False
    mock_ses.send_email.assert_called_once_with(
        template_id="verification-email",
        to_email="alice@acmecorp.com",
    )

def test_disallowed_domain_rejected(client, db):
    r = client.post("/auth/register",
        json={"email": "bob@gmail.com", "password": "ValidPass123!"})
    assert r.status_code == 422
    assert r.json() == {
        "error": "email-domain-not-allowed",
        "allowed-domain": "acmecorp.com",
    }
    assert db.query(User).count() == 0

6.4 Substrate-native validation

При попытке коммитить — substrate-нативный hook проверяет SR-ссылки в TR и наличие негативного TC:

[pre-commit] Verifying TR linkage:
  ✓ TR-101 has parent.id: SR-01 (exists, approved)
  ✓ TR-101 implements-spec: [SPEC-API-01, SPEC-SEC-01] (exist, approved)
[pre-commit] Verifying negative TC presence:
  ✓ SR-01.verified-by includes TC-002, TC-004 (negative)
✓ Commit allowed

Phase 7 — QG-2 verified-by-TC

7.1 CI запускает TC

[CI] pytest acmecorp-login.src/tests/auth/test_registration.py
  test_allowed_domain_succeeds ............... PASSED
  test_disallowed_domain_rejected ............ PASSED

[CI] Bot обновляет last-run в TC файлах:
  TC-001: last-run.result = pass, requirement-version = 1.0
  TC-002: last-run.result = pass, requirement-version = 1.0
  TC-003: last-run.result = pass, requirement-version = 1.0
  TC-004: last-run.result = pass, requirement-version = 1.0

7.2 Spot-check (Правило 5 Core)

Раз в спринт инженер вручную запускает 5 случайных passing TC и сверяет фактический результат с SR:

$ tausik tc spot-check --sprint current --count 5

Selected (random): TC-001, TC-008, TC-012, TC-019, TC-024.
Running manually...
  TC-001: pass (matches SR-01 expected)
  TC-008: pass (matches SR-02)
  TC-012: pass (matches SR-03)
  TC-019: pass (matches SR-05)
  TC-024: pass (matches SR-06)

✓ Spot-check passed: 5/5.

7.3 Promote SR-01 → verified

$ tausik req promote --to verified --requirement SR-01

QG-2 verified-by-TC:
  ✓ SR-01 ссылается на approved ADAPT-001
  ✓ Pos TC TC-001, TC-003: pass
  ✓ Neg TC TC-002, TC-004: pass
  ✓ TC проверяют поведение (не реализацию)
  ✓ Spot-check passed для current sprint
  ✓ requirement-version (1.0) pinned

[architect approves]
✓ SR-01 status: approved → verified
✓ COVERAGE.md updated

Phase 8 — Delta-TZ

8.1 Клиент через неделю

# TZ-2026-051 — Дополнение к TZ-2026-042
Базовый: TZ-2026-042

## §2 (изменение)
### ФТ-001 (расширение)
Дополнительно разрешить @subsidiary.acmecorp.com (дочерняя компания).
Whitelist расширяется до 2 доменов.

8.2 Delta-ADAPT

$ tausik req adapt-from-tz --tz TZ-2026-051 --parent-adapt ADAPT-001

[claude-opus-4-7] Reading delta-TZ + parent ADAPT-001...
[claude-opus-4-7] Generating delta Forward... 1 section (§2.1 extension).
[claude-opus-4-7] Generating delta backward... 1 finding:
  B-008 (scope): subsidiary email — какой регистр case-sensitivity?
                 Тот же что и main, или явно разный?

Generated draft: ADAPT-001-delta-1.

После 1 итерации с клиентом — ADAPT-001-delta-1 → approved.

8.3 Impact analysis

$ tausik req impact --delta TZ-2026-051

Impact Analysis:
  Affected BR: BR-01 (расширяется scope)
  Affected SR:
    - SR-01: уточнение (whitelist 1 → 2 domains)
    - status downgrade: verified → approved (требует rerun TC)
  Affected TC:
    - TC-001..TC-004: requirement-version 1.0 → 1.1 (re-pin после updates)
    - 2 новых TC нужны: subsidiary domain (pos + neg)
  Affected TR:
    - TR-101: completed; нужна new TR-115 для расширения validation
  Affected SPEC:
    - SPEC-SEC-01: allowed-domains [acmecorp.com] → [acmecorp.com, subsidiary.acmecorp.com]

8.4 Apply delta

Архитектор открывает изменения с маркером [delta:TZ-2026-051]. AI обновляет SR-01 (расширяет whitelist), генерирует 2 новых TC. Реализация в TR-115. CI прогоняет TC, bot обновляет last-run. После spot-check — SR-01 v1.1 → verified снова.


Phase 9 — QG-4 acceptance

9.1 Через 4 недели после release

$ tausik req evaluate start --release v1.0

Measurement window: 4 weeks since 2026-05-15

BR-01: Самостоятельная регистрация
  KPI: Time-to-first-login
  Target: < 2 minutes (P95)
  Actual: 1.4 minutes (P95)
  Achievement: 143% (beat target)

BR-02: Secure MFA
  KPI: % users with 2FA enabled within 7 days
  Target: ≥ 95%
  Actual: 97%
  Achievement: 102%

9.2 QG-4 report + adversarial

AI генерирует acceptance report. Adversarial critic находит: «recovery через admin не покрыт TC, верифицирующим full flow с tickets». Архитектор соглашается → создаёт mini-delta для добавления acceptance TC.

9.3 Sign-off

После закрытия findings клиент подписывает acceptance. BR → status accepted.

acmecorp-login.req/
├── QG-4-REPORT-v1.0.md          # архив отчёта
└── lessons/2026-Q2.md           # lessons learned

Финальные артефакты

acmecorp-login.req/
├── adapt/
│   ├── ADAPT-001-main.md                  (status: frozen)
│   └── ADAPT-001-delta-1.md               (status: frozen)
├── br/
│   ├── BR-01-self-service-registration.md (status: accepted)
│   └── BR-02-secure-mfa.md                (status: accepted)
├── sr/
│   ├── SR-01-email-domain-validation.md   (v1.1, verified)
│   ├── SR-02-totp-enrollment.md           (v1.0, verified)
│   ├── SR-03-totp-verification.md         (v1.0, verified)
│   ├── SR-04-password-recovery-via-admin.md (v1.0, verified)
│   ├── SR-05-rate-limiting-failed-logins.md (v1.0, verified)
│   ├── SR-06-audit-logging.md             (v1.0, verified)
│   └── SR-07-data-residency-ru.md         (v1.0, verified)
├── specs/
│   ├── ui/SPEC-UI-01-login-flow.md        (verified)
│   ├── api/SPEC-API-01-auth.md            (verified)
│   ├── data/SPEC-DATA-01-user-model.md    (verified)
│   └── sec/SPEC-SEC-01-auth-policy.md     (verified, v1.1)
├── tests/
│   └── TC-001..TC-028                     (28 TC, 100% passing)
├── tz/
│   ├── TZ-2026-042.md                     (initial, immutable)
│   └── TZ-2026-051.md                     (delta, immutable)
├── elicitation/                           (Phase 0 артефакты)
├── lessons/2026-Q2.md                     (Phase 9 lessons)
└── QG-4-REPORT-v1.0.md                    (acceptance report)

Метрики проекта

После accepted release:

МетрикаЗначение
RDLT (TZ signed → all SR verified)11 days
Coverage Velocity100% за 2 sprint’а
Hallucination Rate (детектированных)0%
Adversarial findings caught (cycle 1)4 high + 2 medium
Test-spec drift на delta-ТЗ0%
Acceptance disputes0 (1 finding, resolved before sign-off)
Cost per BR$0.46 (gen) + $0.18 (critic) = $0.64
Total AI cost~$8.50
BRs accepted2/2
Дней до accept35

Что показывает этот пример

  1. Прозрачность — каждый артефакт имеет provenance, каждый переход — gate с явными условиями.
  2. Скорость — декомпозиция approved ADAPT — 28 секунд + 2 цикла adversarial.
  3. Trace — от строки в ТЗ до passing TC за 2 клика (substrate-агрегированный запрос).
  4. Delta-ТЗ — затронутые SR/SPEC/TC/TR — автоматически вычисляются.
  5. Закрытие петли — QG-4 связывает back к business outcomes (KPI achievement).
  6. AI-нативно — критик и генератор — разные модели (изоляция); spot-check ловит то, что автоматика не видит.

Что дальше


Walkthrough RENAR 1.0-draft — renar.tech