Commit Graph

1032 Commits

Author SHA1 Message Date
63a839e3b0 fix(translate): fail closed on missing source and silent run success
Stop preview/env fallbacks when a configured datasource is gone, skip the
duplicate final insert after streaming, and surface retry/scheduler/LLM
edge cases as FAILED instead of COMPLETED.
2026-08-20 15:37:16 +03:00
585a00c537 semantic-curation: fix anchors, metadata, and relations across backend + specs
- Replace legacy @PURPOSE with @BRIEF across 241 files
- Add missing [C:N] complexity tiers to function contracts in core modules
- Fix tombstone contracts: add @STATUS DEPRECATED to 5 deprecated anchors
- Resolve 7 unresolved @RELATION edges in executor.py (DictionaryManager, TranslationPreview, etc.)
- Fix flat hierarchical IDs in 4 test files (22 test functions)
- Fix invalid tags/relations in logger.py (@ADR, @CONSEQUENCES, DISABLED_BY)
- Rebuild semantic index: 9,576 contracts, 4,742 edges, 0 parse warnings
2026-08-20 11:45:15 +03:00
82a519a347 feat(scenarios): complete editor execution and analytics 2026-08-20 11:32:26 +03:00
455a56856f fix(agent): report THREAD_REPAIRED as lifecycle error code
The send-path repair branch set _request_result but not
_request_error_code, so the AGENT_REQUEST_FAILED lifecycle event fell back
to the misleading 'agent lifecycle failure'. Set THREAD_REPAIRED so logs
and middleware show the real outcome.
2026-08-19 20:14:50 +03:00
a619c0afb2 fix(agent): use async aupdate_state for checkpoint repair
The repair paths (send-path _repair_pending_tool_calls and resume fallback)
called graph.update_state — the SYNC method — which internally invokes
AsyncPostgresSaver.get_tuple() and raises InvalidStateError ('Synchronous
calls to AsyncPostgresSaver are only allowed from a different thread').
The repair therefore always failed (surfacing as 'Event loop is closed' +
a dangling aget_tuple coroutine) and broken threads stayed broken.

Switch both repair sites to agent.aupdate_state (async checkpointer
interface) and align the mocked agent in tests. Verified live: aupdate_state
repaired the broken checkpoint of conversation 69651ca1 (pending calls → 0).
2026-08-19 20:08:52 +03:00
7cc3297f1e fix(agent): recover broken threads and lazily create scenario runs
Two recurring failures from live logs (conversations 69651ca1 / a8c0dff8):

1. A checkpoint whose AI messages carry tool_calls without ToolMessages
   (run crashed after the LLM emitted a call) makes every send raise
   INVALID_CHAT_HISTORY with no recovery. The send path now repairs the
   thread via _repair_pending_tool_calls: pending calls are answered with
   synthetic error ToolMessages (THREAD_REPAIRED) so the user can retry.

2. Scenario tools scheduled from plain chat (no build_dashboard_test_scenario
   UI intent) had no durable AgentRun, so the resume fallback refused with
   SCENARIO_RUN_REQUIRED. _ensure_scenario_run now lazily creates the run
   from the tool args (dashboard_context from scenario_json for
   validate/resolve), mirroring the UIContextV2 scenario contract.
2026-08-19 20:02:12 +03:00
614f675f64 fix(agent): detect truncated scenario JSON for clear retry feedback
Observed in a live checkpoint: the pending scenario_validate tool call
carried a scenario_json that the LLM stream cut mid-document (ended
inside the unclosed outer object, len 3837). _parse_json_value failed
with a generic 'Could not extract JSON value' that neither the operator
nor the LLM could act on. Add _looks_truncated (unbalanced structure /
unterminated string at end) and report 'truncated/incomplete JSON' with
input length, so the model regenerates the full document.
2026-08-19 19:52:16 +03:00
9b0350b3b0 fix(agent): send search param instead of ignored q to /api/dashboards
The backend route binds the search query to `search`; a bare `q` param is
not bound, so search_dashboards and prefetch_dashboards silently returned
the unfiltered catalog (e.g. query 'Sales' listed all 11 dashboards).
Switch both to `search` and update the URL-contract test.
2026-08-19 19:31:32 +03:00
e291ba757f fix(agent): full-catalog dashboard search and working LLM retry
- search_dashboards: call /api/dashboards with page_context=other and
  page_size=100 so the profile 'My Dashboards Only' filter can no longer
  hide the whole catalog; parse available_total/effective_profile_filter
  and report hidden-by-filter instead of a false 'no dashboards' answer
- prefetch_dashboards: same full-catalog context; fix dead code where
  data=resp.json() sat after return '' inside the error branch, making
  every 200 response raise NameError and the prefetch always return ''
- llm-status: ?force=1 bypasses the 30s health cache so the 'Retry now'
  button performs a fresh probe instead of re-reading the stale status;
  frontend keeps a single retry interval (previously stacked intervals
  decayed the countdown faster than 1/s and fired duplicate probes)
- tests: agent tool/prefetch, backend route bypass + force param,
  frontend retry/force coverage
2026-08-19 19:21:00 +03:00
615f3ccd25 fix: graceful fallback when Superset rejects changed_on_dttm filter during incremental sync 2026-08-19 17:38:35 +03:00
488a8f349b test(backend): raise coverage to 95%+ statements and branches (97.8%/95.0%)
- ~60 new/extended test files across api, core, plugins, services, schemas:
  routes, superset clients, task_manager, lineage, git, translate,
  dashboard-testing, load-testing, migration, llm_analysis, scheduler, ssl
- .coveragerc: enable branch coverage; exclude src/__tests__ (test files)
  and src/scripts (CLI/ops tools) from the denominator
- bug fixes found while testing:
  * settings: PUT /settings/reports registered under duplicated prefix
  * schemas/lineage: FleetReportDTO missing run_status (route always 500)
  * dashboard_testing/baseline_inheritance: visual entry read wrong field
  * superset_client/_databases: logger extra name shadowed LogRecord attr
  * routes/datasets: _yaml_string_paths recursion without yield from
  * translate/sql_generator: restore explicit-type timestamp contract
  * baseline_catalog: remove unreachable dashboard_id fallback
- conftest fixes: pytest_plugins to rootdir conftest (pytest 9), test
  filename collision, TMPDIR-safe integration fixtures
2026-08-19 17:14:32 +03:00
dd9df0fc5e feat(env-widget): dashboard stats widget with per-env counts, health probe and profile-filter reference info
- Replace the global env <select> in TopNavbar with an expandable
  EnvironmentStatsWidget showing per-env total/mine/published/drafts
  and health status (latency, unreachable), preserving env switching.
- Add GET /api/environments/stats: per-env counts (profile-actor matched)
  + lightweight health probe, gathered concurrently with an 8s probe
  timeout and a process-local TTL cache (30s, coalescing) so the full
  Superset dashboard catalog is not re-fetched on every dropdown open.
- Add available_total to GET /api/dashboards so grids can show how many
  dashboards exist when the profile-default filter hides everything.
- Share ProfileFilterBanner across the dashboards hub and validation
  task form: 'showing X of Y' reference info + explicit Show all /
  Restore filter actions.
- Russian plural forms for dashboard counts (pluralRu helper) and
  compact 'Опубл.' label; i18n keys en/ru.
- Ignore :memory:test_* SQLite test artifacts and drop them from the index.
- Tests: env stats endpoint (incl. caching), widget, model fallback,
  plural helper, api client, integration.
2026-08-19 14:40:14 +03:00
a571ff8175 fix(search): global search queries with envId and bypasses profile filter
- handleSearchInput now receives the selected envId, so the debounced
  search actually fires API requests instead of hitting the !envId guard
  and clearing results immediately.
- The dashboard section of the global search sends page_context=other,
  apply_profile_default=false, override_show_all=true (same pattern as
  DashboardHubModel.loadDashboardSearchOptions), so the "show only my
  dashboards" profile filter no longer zeroes out dashboards that lack
  owner metadata.
- Updated unit tests: debounce now asserts API calls + profile-off flags.
2026-08-19 11:00:33 +03:00
81ba94684f feat: sed-мутации датасетов, правки миграции и фиксы
- Dataset viewer: sed-замена (find→replace) по всем/выбранным/текущим датасетам
  с обязательным визуальным предпросмотром и целями (sql/metrics/yaml); сохранение
  и выбор именованных правил (sedRules store + SedRuleEditor).
- Migration: literal-замена в dataset YAML при переносе; рескан ID чартов/датасетов
  перед миграцией + метрика средней длительности синка (GET /migration/sync-stats);
  логическая группировка опций (маппинги БД, сервер изменений, rescan) под галочками.
- Fix: дашборды хаба скрывались дефолтным профиль-фильтром show_only_slug_dashboards=true
  (теперь false); мастер миграции не грузил дашборды предзаполненного источника;
  потеря терминального task_status из-за утечки pending-корутин в /ws/logs (панель
  результата не появлялась); горизонтальный скролл в MappingTable; чистая per-env
  ошибка в mapping coverage.
- Backend: record_sync_duration + alembic-миграция sync-duration; literal_replace модуль.
2026-08-19 10:29:28 +03:00
a5764eb008 fix(orchestration): make KV-cache rules explicit; workers long-lived everywhere
- skill §11 rewritten: one invariant (byte-identical prefix) + explicit
  preserve/invalidate lists + discipline (load self-orchestration once;
  persona/toolFilter/model fixed for a worker's whole life)
- worker skills: "disposable context" -> "long-lived context"; role lines
  now say "leaf, long-lived, refined in place via send_message"
2026-08-18 16:24:19 +03:00
e3de06832a feat(orchestration): long-lived workers across all roles + KV-cache economics
- contracts: Self.Worker.Verify/Curate now carry the long-lived invariant
  and "refined in place" brief (matching Implement)
- skill §9: cycle says "read freely" + "spawn long-lived worker, refine"
- skill §11 (new): token & KV-cache economics — long-lived send_message
  keeps the prefix byte-identical (warm cache), fork invalidates it,
  spawn starts cold; merge envelopes; keep surface lean
2026-08-18 16:15:23 +03:00
b232c347fd feat(orchestration): make workers long-lived, not disposable
Workers are continuable long-lived children: spawn once, refine in place
via send_message as the feature evolves; a worker's own session persists
and compacts independently. Re-spawn only when the context is poisoned.

- skill §3: delegation tree rewritten — "refine, don't re-spawn"
- skill §5: "refine, don't re-spawn" coordination rule
- skill §7: stalled worker → send_message (keep context), fresh spawn
  only for poisoned context
- contracts: Self.Worker.Implement is "long-lived, refined in place";
  add long-lived invariant
2026-08-18 16:11:07 +03:00
8a2a12964c fix(orchestration): architect reads freely; delegate execution, not reading
Drop the "never read raw files" rule — it was a false economy. The
architect's context is large and auto-compacting, so reading is cheap and
necessary for decomposition and verification. The real boundary is
EXECUTION (edits/builds/tests) stays with workers, not READING.

- skill §1/§6/§10: "read freely" replaces "never read raw files";
  prefer read_outline/search_contracts to locate, read/grep/glob to understand
- @RATIONALE reframed: reading is cheap; only DECISIONS must not live
  solely in context (they go to files)
- contract: invariant becomes "reads freely for decisions, delegates execution"
2026-08-18 15:52:06 +03:00
ca1761f490 fix(orchestration): harden thin-context protocol against observed drift
Session-log review found the orchestrator diverging from its own design.
Encode every divergence as a rule + invariant:

- no polling: get_goal/list_agents are state tools, not completion checks
  (settlement/report are the signals) — was 101 get_goal + 98 list_agents
- no raw reads: structure via read_outline/search_contracts; file CONTENT
  is delegated (was 77 read vs 1 read_outline)
- <RESULT> enforcement: a worker result with no envelope is blocked
  (was 4/19 envelopes)
- closed role taxonomy: only Implement/Verify/Curate (was ad-hoc
  "code reviewer"/"auditor"/"adversarial")
- fork semantics: fork inherits MY context, not a stalled worker's;
  no "takeover" via fork
- interrupt only to redirect; let workers finish (was 7 interrupts)
- decision memory written by me to files (was zero file writes)
- skill hygiene: load self-orchestration once; never load worker skills
- cross-workspace: point Axiom at the target or delegate all reading
2026-08-18 14:51:50 +03:00
f1ee96fda8 fix(orchestration): stop workers from inheriting the orchestrator role
Child subagents join the parent's preset composition, so by default they
inherited the orchestrator persona AND the delegation tools — and drifted
into orchestrating instead of working (observed: a "worker" called
list_agents/get_goal/send_message and spawned its own grandchildren).

Fixes:
- preset: subagent/subagent_fork now carry a role-agnostic worker `persona`,
  `toolFilter.deny` for all delegation/coordination tools, and `maxDepth: 1`
  (children cannot spawn grandchildren) — hard enforcement at the boundary
- skill: every worker prompt opens with a mandatory role-reset block
- contracts: Self.Worker.Implement/Verify gain a LEAF invariant (no subagents,
  no delegation tools)
2026-08-18 14:41:37 +03:00
dff97e58da chore: gitignore generated semantic-index and bundle artifacts 2026-08-18 12:45:06 +03:00
2a0f334717 chore: remove hardcoded Fernet key and client cert
- ENCRYPTION_KEY: smoke test generates a fresh key inline; templates use a placeholder
- drop RUSAL_ROOT.cer (client-specific public cert) + gitignore it
2026-08-18 12:32:06 +03:00
a995e6f269 chore: remove tracked junk and add gitignore rules
Drop service/debug files accidentally tracked in the previous checkpoint:
- session.jsonl (agent transcript)
- artifacts/ (integration-test debug logs)
- research/paper.pdf (binary blob)
- .npmrc (machine-local config)

Add .gitignore rules for session.jsonl, artifacts/, .npmrc, *.pdf
so they cannot be re-committed.
2026-08-18 12:27:03 +03:00
977f3d6d75 chore: checkpoint working tree onto master
Carried over from 042-dashboard-scenario-registry:
- dashboard/migration backend changes + tests (dataset_key_sync)
- specs updates; drop generated doxygen artifacts
- research notes, integration artifacts, session log
2026-08-18 12:20:42 +03:00
604b3dc706 feat(orchestration): add implementer and verifier workers
Complete the role graph with the two remaining leaf workers.

Skills:
- self-implementation: implement inside @PRE/@POST/@INVARIANT guardrails,
  verifiable edit loop, decision-memory preservation, <RESULT> envelope
- self-verification: orthogonal falsifiable verification, hardcoded
  fixtures, @TEST_INVARIANT traceability, anti-tautology

Presets (staged under docs/design/*-preset; installed to ~/.dsh/.agent-presets):
- implementer: native wire, leaf, bash for the verifier
- verifier: native wire, leaf, bash for pytest/vitest

Contracts (self-orchestration-contracts.md, now 13 contracts):
- Self.Implement.{EditLoop,DecisionMemory}
- Self.Verify.{Traceability,AntiTautology}
- worker edges: Implement/Verify DISPATCHES -> their sub-contracts
2026-08-18 09:17:48 +03:00
e6c77cc3da feat(orchestration): self-orchestration flow — orchestrator + curator
Add the thin-context orchestration protocol as loadable skills,
agent presets, and verifiable GRACE-Poly contracts.

Skills:
- self-orchestration: architect protocol (memory hierarchy, delegation
  decision tree, <RESULT> envelope, park-don't-poll, anti-loop)
- semantic-curation: curator protocol (audit → one-file repair → verify →
  rebuild → health report; anti-corruption invariants)

Presets (staged under docs/design/*-preset; installed to ~/.dsh/.agent-presets):
- orchestrator: native wire, tuned compaction (0.75/0.20), full toolset
- curator: native wire, leaf (no delegation), bash reserved for git rollback

Contracts (docs/design/self-orchestration-contracts.md, indexed + audited):
- Self.Orchestrator, Self.Worker.{Implement,Verify,Curate}
- Self.Curation.{Loop,HealthReport,AntiCorruption}
- Self.Contract.{ResultEnvelope,DecisionTree}
2026-08-18 09:07:14 +03:00
1dd78ca548 fix integration test failures 2026-08-17 16:09:03 +03:00
ea05a42c81 fix frontend environment fallbacks and remove deprecated code 2026-08-17 15:08:34 +03:00
2e8628b2c8 tasks 2026-08-13 18:49:37 +03:00
c32b7ef509 feat(translate): extend run metrics with observed flow stats; test hardening
- backend: aggregate cache_hits/observed_runs/source_records_read/eligible/
  translated/same_language_skipped/insert_rows_* preserving NULL for
  historical runs; drop legacy translate plugin module
- frontend: history page metric cards + RunOutcomeCompact per-run summary,
  totals with observed-scope notice; tabular numbers
- tests: fix banner date-format expectations, api-key env-scope fixture,
  rate-limiter cache pollution pinning, chart/candidates guards
- specs: sync dashboard-testing openapi contract
2026-08-13 08:23:43 +03:00
6336de9c24 fix(translate): correct preview responses and target DB selection 2026-08-11 12:34:00 +03:00
e7d33ce4c8 chore(db): drop orphaned dataset-review and connection_configs tables
Remove dead schema left behind by removed features:
- dataset-review family (dataset_review_sessions, dataset_profiles, and
  related children) from c3ad0afc — its non-cascading FKs broke environment
  deletion with ForeignKeyViolation
- connection_configs from 74e64622

Both are unreachable from the app (no models register them).
2026-08-11 10:55:52 +03:00
3f12d52fbc docs: reconcile verification program architecture 2026-08-11 09:02:53 +03:00
1145a1922c docs: close scenario agentic workflow contracts 2026-08-10 20:06:27 +03:00
e52c5777ba feat(maintenance): fan out API starts to prod 2026-08-10 15:56:03 +03:00
9450559da5 feat(maintenance): improve event history and templates 2026-08-10 15:05:20 +03:00
7924ec5b10 fix(logs): reduce production log spam — agent llm-config polling, scheduler plumbing
- middleware: suppress structured REASON/REFLECT framing for high-frequency
  pollers (/api/agent/llm-config, /api/tasks/{id}, health/summary,
  session/activity, settings/consolidated); fixes tasks/{id} never matching
- agent: _fetch_llm_config treats 401/403 as terminal (no retry, log once),
  bounded backoff 5s/15s/60s on connect/timeout/5xx; langgraph_setup logs
  auth failure once per process
- scheduler: auto-end plumbing lines (executed/scan triggered) -> DEBUG
- thumbnail: Superset 4xx rejections logged at DEBUG instead of EXPLORE
2026-08-10 12:28:07 +03:00
4bc244c228 fix(examples): maintenance API scripts — error handling, JSON safety, docs
- bash: propagate api_call failures (exit 1 on 400/401/403/404/network),
  write diagnostics to stderr, escape message for JSON safety, help without
  API key
- python: argparse options after subcommand (parents), single error message
  per failure, network errors without traceback, idempotent already_completed
- move scripts to examples/maintenance/ with README instructions
- backend: correct stale envelope-shape comment in maintenance schemas
2026-08-10 12:04:50 +03:00
db255ea4e6 feat(maintenance): ui/ux audit improvements for BI analyst persona
- read-only access to /maintenance for analysts (sidebar + hidden management)
- hub badge: message tooltip, link to events, accessible aria-label, localized end
- keep hub badge fresh via shared maintenance WS (init on dashboards page)
- events table: message column, auto-end indicator, localized statuses
- confirm dialog before starting maintenance with affected-dashboards summary
- surface load errors inline; localize store toasts
- auto-end discoverability hints in form and table
- form: multiple tables, end>start validation, timezone note
- status colors: active -> warning; completed tab dashboards expandable
- settings: timezone select, fieldset, localized units/aria labels
- backend: expose auto_end in event items, message in banner states
2026-08-10 12:04:43 +03:00
512e9223e3 feat(maintenance): configurable date format for banner timestamps 2026-08-10 11:22:48 +03:00
71a76cc784 fix(git): address dashboards by stable slug, hide git actions for slugless dashboards 2026-08-10 11:22:41 +03:00
d733a1a745 chore: remove legacy semantic skills 2026-08-10 09:19:07 +03:00
3421484347 chore: synchronize remaining workspace updates 2026-08-10 07:29:08 +03:00
1c577e8561 docs(semantics): normalize code contracts 2026-08-10 07:28:05 +03:00
093f7f600f fix(maintenance): harden banner lifecycle and guarded migrations
- Guard maintenance Alembic operations for create_all-only tables on clean DBs
- Add guarded verification_runs.fanout_plan_id backfill migration
- Improve maintenance banner rendering, chart management, orchestration, and API routes
- Expand assistant maintenance tool and edge-case coverage

Tests: cd backend && source .venv/bin/activate && python -m pytest -q tests/test_maintenance_api.py tests/test_maintenance_service.py tests/api/test_assistant_tool_maintenance.py tests/api/test_maintenance_routes_edge.py (77 passed)
2026-08-09 08:22:16 +03:00
ffa4456a62 docs(specs): add machine contract reconciliation gate
- Validate and repair OpenAPI YAML contracts for 038, 043, and 046
- Canonicalize 038 JSON schema and fixtures around scenario_key,
  content_hash, and logical_step_id; validate all fixtures with jsonschema
- Regenerate 038 validation evidence for compiler scope only
- Add reconcile_contracts.py for repeatable OpenAPI/JSON/fixture checks
- Replace raw CreateScenario payload with server-owned handles and document
  transactional outbox/materialization saga for Registry-to-git persistence
- Record reconciliation outcome in REVIEW-042-047-CLOSURE.md
2026-08-09 08:19:02 +03:00
f7e539440e feat(tooling): rewrite merge_spec.py — batch spec merging + new package support
Rewrite merge_spec.py to merge one or many feature spec packages into a
single review file.

Batch modes:
- single number: python merge_spec.py 038
- inclusive range: python merge_spec.py 036-041
- explicit list: python merge_spec.py 036 038 044
- by dir name: python merge_spec.py 042-dashboard-scenario-registry
- all: python merge_spec.py all
- custom output: python merge_spec.py 036-041 -o out.md

Handles the new spec package structure that plain *.md merging missed:
- includes contracts/openapi.yaml (YAML), contracts/ux/* (decisions.md),
  prototype/index.html + prototype/manifest.md
- skips .json/.py/.zip/.pyc and __pycache__ (fixtures/code/binaries)
- canonical per-feature order: spec -> ux_reference -> checklists ->
  UX contracts -> plan -> research -> data-model -> modules -> openapi ->
  quickstart -> traceability -> tasks -> prototype
- missing numbers warn+skip; dedup; per-feature grouping in one output

Verified: 043 (14 files), 036-041 (6 features/104 files), 036-047 (12/186),
all (50/572) with no .json/.zip/.pyc leakage.
2026-08-09 11:06:36 +07:00
4858992e15 docs(specs): cross-spec canonicalization pass — reconcile 038 core with 042-047
Reconcile the stale 038 compiler-layer model with the 042-047 lifecycle and
its normative documents (not just data-model).

038 -> clean IR/compiler layer:
- identity: scenario_id slug -> scenario_key (semantic); scenario_id (UUID)
  and revision_id (UUID) assigned by 042 at Save; compiler emits content_hash
- ScenarioStep: add logical_step_id (immutable UUID) + step_key/position/
  step_content_hash; runtime VlmFinding/HumanDisposition moved to 044
- VlmAnalysisSpec/ScreenshotCaptureSpec stay (WHAT); runtime capture/VLM/
  disposition endpoints marked deprecated -> 410 MOVED_TO_044
- CompileRequest: agent_run_id no longer required (optional provenance,
  source_type: agent_run|editor|migration|api)
- runtime evidence = Artifact(owner_type=scenario_run), never authoring DraftPack
- validation.md PASS nullified (self-contradictory COMPLETE vs OPEN);
  refocused as compiler-layer PASS only; T057-T059 moved to 044; T046 rewritten

042/043/044/045 normative (spec/research/checklists/ux/prototype/tasks):
- replace revision_hash/parent_revision_hash/scenario_revision_hash with
  revision_id/content_hash/parent_revision_id everywhere
- 044: HumanCheckpoint (confirm/false_positive/inconclusive) distinct from
  ActionApprovalGate; runner pins revision_id+content_hash
- 047: triage split (investigation_status/classification/resolution), false_positive
  vocabulary; /scenarios/{id}/health|trends|recurring-failures

Update REVIEW-042-047-CLOSURE.md with canonicalization pass status.
2026-08-09 10:55:53 +07:00
9889e09d87 docs(specs): renumber 042-043 to 048-049, add scenario lifecycle specs 042-047
- Renumber: 042-rls-management-workspace -> 048, 043-idm -> 049
  (internal refs updated; RLS research '043 Explainability' corrected)
- Add 042 Scenario Registry & Lifecycle: persistence, list/detail,
  immutable revisions (revision_id/content_hash), CreateScenario
  (Save->Register), lifecycle state machine, staleness via 037/041, health
- Add 043 Scenario Editor UX: hybrid edit model C, WorkingDraft save
  (no arbitrary-draft bypass), SetParameter/AddStep/RemoveStep ops,
  constrained assertions, visual DAG, agent edit, Revalidate migration
- Add 044 Scenario Execution Engine: ScenarioRun/StepRun, deterministic
  runner, RunnerPlan derived from revision (not stored source of truth),
  ActionApprovalGate vs HumanCheckpoint, generic artifact owner, worker
  lease/idempotency, logical_step_id, retry closure, result aggregation
- Add 045 Run Monitor & Results UX: config, live SSE monitor, human
  actions, result+provenance, history/compare, Global Run Operations Center
- Add 046 Automation & Operations: schedules/triggers/API trigger, CRUD,
  scheduler semantics, notification events, layered retention tiers, UI
- Add 047 Triage & Analytics: strict flakiness, immutable fingerprint,
  triage split, /scenarios/{id}/health|trends|recurring-failures
- Add specs/REVIEW-042-047-CLOSURE.md mapping all review gaps to fixes
- Update PRODUCT_ROADMAP for 042-049

Each spec: spec/data-model/research/plan/tasks/ux/traceability/quickstart/
checklists + contracts/modules + openapi + interactive prototype.
2026-08-07 18:30:32 +07:00
7487887e61 docs(examples): add maintenance API spec and Russian usage instructions to example scripts 2026-08-07 17:10:25 +07:00