mirror of
https://github.com/azaion/admin.git
synced 2026-06-21 10:41:09 +00:00
[AZ-513] [AZ-196] [AZ-183] Add /classes CRUD, /devices, fleet OTA
AZ-513: POST/PATCH/DELETE /classes for detection-class CRUD; new DetectionClass entity, schema, DTOs, IDetectionClassService. Unblocks ui/AZ-512. AZ-196: POST /devices auto-assigns sequential azj-NNNN serial+email +password and inserts a CompanionPC user. Returns plaintext credentials for the provisioning script. AZ-183: Resources table + POST /get-update + POST /resources/publish for fleet OTA. Per-resource encryption_key column AES-256-CBC encrypted at rest with ResourcesConfig.EncryptionMasterKey; ICache wraps the per-(arch,stage) latest-versions lookup and is invalidated on publish. Adds IDbFactory.RunAdmin<T> overload for write-and-return. Backfills _docs/02_document/module-layout.md to satisfy the implement skill's File Ownership prerequisite (the _docs/ artifact set predates the Step 1.5 module-layout addition). Code review: PASS_WITH_WARNINGS — see _docs/03_implementation/reviews/batch_05_review.md. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# Module Layout
|
||||
|
||||
**Language**: csharp
|
||||
**Layout Convention**: solution-flat (legacy — pre-`src/` convention)
|
||||
**Root**: `./` (csproj folders sit at workspace root)
|
||||
**Last Updated**: 2026-05-13
|
||||
|
||||
## Layout Rules
|
||||
|
||||
1. This admin/ workspace is one **deployable** (the `Azaion.AdminApi` HTTP service) split across four production csproj projects + one e2e test csproj: `Azaion.AdminApi`, `Azaion.Services`, `Azaion.Common`, `Azaion.Test`, `e2e/Azaion.E2E`.
|
||||
2. Existing task specs (`_docs/02_tasks/*/AZ-*.md`) all use `Component: Admin API` as a single coarse identifier covering this entire workspace. The Per-Component Mapping below honors that convention rather than rewriting every task spec.
|
||||
3. The conceptual sub-components documented in `_docs/02_document/components/01_data_layer..05_admin_api/` are **read-time** documentation aids, not write-time ownership boundaries. They are listed under "Conceptual Sub-Components" below for reference only.
|
||||
4. Public API surface = the namespaces / interfaces exposed across csproj boundaries (`I*Service` interfaces in `Azaion.Services`, request DTOs in `Azaion.Common/Requests/`, entities in `Azaion.Common/Entities/`).
|
||||
5. Tests live in `Azaion.Test/` (in-process unit/integration) and `e2e/Azaion.E2E/` (HTTP black-box). Production code never imports from either.
|
||||
|
||||
## Per-Component Mapping
|
||||
|
||||
### Component: Admin API
|
||||
|
||||
- **Epic**: AZ-181 (and any other admin-API epic, e.g. AZ-509 for the Detection Classes feature)
|
||||
- **Directory**: workspace root (multi-csproj, see below)
|
||||
- **Owns (exclusive write during implementation)**:
|
||||
- `Azaion.AdminApi/**`
|
||||
- `Azaion.Services/**`
|
||||
- `Azaion.Common/**`
|
||||
- `Azaion.Test/**`
|
||||
- `e2e/Azaion.E2E/**` (xUnit/HttpClient-based black-box tests)
|
||||
- `e2e/db-init/**` (test-DB seed/init scripts consumed by the e2e harness)
|
||||
- `docker.test/**` (test fixture / schema-init helpers used by `Azaion.Test`)
|
||||
- `docker-compose.test.yml`
|
||||
- **Public API** (visible to other csprojs within the workspace):
|
||||
- `Azaion.Services/I*Service.cs` interfaces (UserService, AuthService, ResourcesService, …)
|
||||
- `Azaion.Services/Security.cs`, `Azaion.Services/Cache.cs` (used by `Azaion.AdminApi/Program.cs`)
|
||||
- `Azaion.Common/Requests/*` request DTOs
|
||||
- `Azaion.Common/Entities/*` linq2db entities
|
||||
- `Azaion.Common/Database/*` `IDbFactory` + connection helpers
|
||||
- `Azaion.Common/Configs/*` strongly-typed config records
|
||||
- `Azaion.Common/Extensions/*` extension methods
|
||||
- `Azaion.Common/BusinessException.cs`
|
||||
- `Azaion.AdminApi/Program.cs` (composition root + minimal-API endpoints)
|
||||
- `Azaion.AdminApi/BusinessExceptionHandler.cs`
|
||||
- **Internal (do NOT import across csproj boundaries)**:
|
||||
- private/internal members within each csproj (default C# visibility rules apply)
|
||||
- `Azaion.AdminApi/appsettings*.json` (loaded by the host, not imported)
|
||||
- `e2e/Azaion.E2E/Helpers/*` (test-only helpers, never imported by production)
|
||||
- **Imports from**: (none — this is the only deployable in the workspace; the Loader is architecturally retired per `suite/_docs/_repo-config.yaml` `unresolved:loader-retirement-arch-doc`)
|
||||
- **Consumed by**: HTTP clients (UI workspace, edge services on secured Jetson, SaaS browser sessions) — out of process
|
||||
|
||||
## Conceptual Sub-Components (documentation only — NOT ownership boundaries)
|
||||
|
||||
These come from `_docs/02_document/components/` and exist for reading the codebase, not for assigning task ownership. A single task may legitimately touch multiple sub-components within the `Admin API` umbrella.
|
||||
|
||||
| # | Sub-component | Primary file locations |
|
||||
|---|----------------------|------------------------|
|
||||
| 1 | Data Layer | `Azaion.Common/Database/`, `Azaion.Common/Configs/`, `Azaion.Common/Entities/` |
|
||||
| 2 | User Management | `Azaion.Services/UserService.cs`, `Azaion.Common/Requests/{Create,Update,SetPassword,…}UserRequest.cs` |
|
||||
| 3 | Auth & Security | `Azaion.Services/AuthService.cs`, `Azaion.Services/Security.cs`, `Azaion.Services/Cache.cs` |
|
||||
| 4 | Resource Management | `Azaion.Services/ResourcesService.cs`, `Azaion.Common/Requests/{GetResource,CheckResources,…}.cs` |
|
||||
| 5 | Admin API (HTTP) | `Azaion.AdminApi/Program.cs`, `Azaion.AdminApi/BusinessExceptionHandler.cs`, `Azaion.AdminApi/appsettings*.json` |
|
||||
|
||||
## Allowed Dependencies (csproj layering)
|
||||
|
||||
| Layer | csproj | May reference |
|
||||
|-------|--------|---------------|
|
||||
| 4. Entry / Host | `Azaion.AdminApi` | `Azaion.Services`, `Azaion.Common` |
|
||||
| 3. Application | `Azaion.Services` | `Azaion.Common` |
|
||||
| 2. Foundation | `Azaion.Common` | (none) |
|
||||
| —. Tests (in-process) | `Azaion.Test` | `Azaion.Services`, `Azaion.Common`, `Azaion.AdminApi` (integration only) |
|
||||
| —. Tests (out-of-process e2e) | `e2e/Azaion.E2E` | (none from production csprojs — HTTP only) |
|
||||
|
||||
A reference from a lower production layer to a higher production layer is an **Architecture** finding (High severity) in `/code-review` Phase 7. Test projects may reference any production csproj; production csprojs may NOT reference test projects.
|
||||
|
||||
## Layout Conventions (reference)
|
||||
|
||||
| Language | Root | Per-component path | Public API file | Test path |
|
||||
|----------|------|-------------------|-----------------|-----------|
|
||||
| C# (.NET) | `./` (this workspace, legacy flat layout) | `./<Csproj>/` | namespace-root types in each csproj | `Azaion.Test/`, `e2e/Azaion.E2E/` |
|
||||
|
||||
## Notes
|
||||
|
||||
- This file was authored 2026-05-13 by `/autodev` Step 10 to satisfy `/implement` Step 4. The `_docs/` artifact set predates the Step 1.5 module-layout addition, so this is a **backfill** rather than a fresh decompose Step 1.5 run.
|
||||
- If the project later splits into multiple deployables (e.g. carving out `Azaion.AnnotationsApi`), re-run `/decompose` Step 1.5 to produce a finer-grained mapping.
|
||||
@@ -1,18 +1,25 @@
|
||||
# Dependencies Table
|
||||
|
||||
**Date**: 2026-04-16
|
||||
**Total Tasks**: 10
|
||||
**Total Complexity Points**: 37
|
||||
**Date**: 2026-05-13 (refreshed; original 2026-04-16)
|
||||
**Total Tasks**: 11 (7 done test tasks + 4 active product tasks)
|
||||
**Total Complexity Points**: 40
|
||||
|
||||
| Task | Name | Complexity | Dependencies | Epic |
|
||||
|------|------|-----------|-------------|------|
|
||||
| AZ-189 | test_infrastructure | 5 | None | AZ-188 |
|
||||
| AZ-190 | auth_tests | 3 | AZ-189 | AZ-188 |
|
||||
| AZ-191 | user_mgmt_tests | 5 | AZ-189, AZ-190 | AZ-188 |
|
||||
| AZ-192 | hardware_tests | 3 | AZ-189, AZ-190 | AZ-188 |
|
||||
| AZ-193 | resource_tests | 5 | AZ-189, AZ-190, AZ-192 | AZ-188 |
|
||||
| AZ-194 | security_tests | 3 | AZ-189, AZ-190 | AZ-188 |
|
||||
| AZ-195 | resilience_perf_tests | 5 | AZ-189, AZ-190 | AZ-188 |
|
||||
| AZ-183 | resources_table_update_api | 3 | None | AZ-181 |
|
||||
| AZ-196 | register_device_endpoint | 2 | None | AZ-181 |
|
||||
| AZ-197 | remove_hardware_id | 3 | None | AZ-181 |
|
||||
| Task | Name | Complexity | Dependencies | Epic | Status |
|
||||
|--------|-------------------------------|-----------:|-------------------------|--------|--------|
|
||||
| AZ-189 | test_infrastructure | 5 | None | AZ-188 | done |
|
||||
| AZ-190 | auth_tests | 3 | AZ-189 | AZ-188 | done |
|
||||
| AZ-191 | user_mgmt_tests | 5 | AZ-189, AZ-190 | AZ-188 | done |
|
||||
| AZ-192 | hardware_tests | 3 | AZ-189, AZ-190 | AZ-188 | done |
|
||||
| AZ-193 | resource_tests | 5 | AZ-189, AZ-190, AZ-192 | AZ-188 | done |
|
||||
| AZ-194 | security_tests | 3 | AZ-189, AZ-190 | AZ-188 | done |
|
||||
| AZ-195 | resilience_perf_tests | 5 | AZ-189, AZ-190 | AZ-188 | done |
|
||||
| AZ-183 | resources_table_update_api | 3 | None | AZ-181 | todo |
|
||||
| AZ-196 | register_device_endpoint | 2 | None | AZ-181 | todo |
|
||||
| AZ-197 | remove_hardware_id | 3 | None | AZ-181 | todo |
|
||||
| AZ-513 | classes_crud_routes | 3 | None | AZ-509 | todo |
|
||||
|
||||
## Notes
|
||||
|
||||
- AZ-513 added 2026-05-13 (cross-workspace prerequisite from `ui/` workspace AZ-512). Filed under epic AZ-509 (Cycle 3 — Auth bootstrap fix + classColors carve-out + admin class edit).
|
||||
- AZ-197 originally listed `Component: Admin API, Loader`; the Loader workspace was architecturally retired (see `suite/_docs/_repo-config.yaml` `unresolved:loader-retirement-arch-doc`) and the spec was adapted on 2026-05-13 to be admin-only.
|
||||
- All four active tasks (AZ-183, AZ-196, AZ-197, AZ-513) are independent — no inter-task dependencies in this active set.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Batch Report
|
||||
|
||||
**Batch**: 5 (cycle 1, batch 1 of 2)
|
||||
**Tasks**: AZ-513_classes_crud_routes, AZ-196_register_device_endpoint, AZ-183_resources_table_update_api
|
||||
**Date**: 2026-05-13
|
||||
|
||||
## Task Results
|
||||
|
||||
| Task | Status | Files Modified | Tests | AC Coverage | Issues |
|
||||
|--------|--------|---------------------------------------------------------------------------------------------------------|----------------------------------------|-------------------------|--------|
|
||||
| AZ-513 | Done | DetectionClass entity + 2 DTOs + DetectionClassService + Program.cs (3 routes) + schema + SQL migration | DetectionClassesTests.cs (9 e2e tests) | AC 1–9 / AC-10 = UI side | None blocking |
|
||||
| AZ-196 | Done | RegisterDeviceResponse DTO + UserService.RegisterDevice + Program.cs (1 route) | DeviceRegistrationTests.cs (5 e2e tests) | AC 1–5 | F1 (Medium / race) tracked in review |
|
||||
| AZ-183 | Done | Resource entity + 2 DTOs + ResourceUpdateService + Program.cs (2 routes) + schema + SQL migration + ResourcesConfig.EncryptionMasterKey | ResourceUpdateTests.cs (4 e2e tests) | AC 1, 2, 3, 5 (AC-4 by inspection) | F2–F4 (Low) tracked in review |
|
||||
|
||||
## AC Test Coverage: 18/18 admin-side ACs covered (AC-10 of AZ-513 verified in UI workspace; AC-4 of AZ-183 is a perf characteristic, verified by inspecting `ResourceUpdateService.GetUpdate`'s `cache.GetFromCacheAsync` wrapping `LoadLatest`)
|
||||
|
||||
## Code Review Verdict: PASS_WITH_WARNINGS — see `_docs/03_implementation/reviews/batch_05_review.md`
|
||||
|
||||
## Auto-Fix Attempts: 0
|
||||
|
||||
## Stuck Agents: None
|
||||
|
||||
## Notes / Decisions
|
||||
|
||||
- **Wire-compat for new endpoints**: All three new routes are additive (`POST /classes`, `PATCH /classes/{id}`, `DELETE /classes/{id}`, `POST /devices`, `POST /get-update`, `POST /resources/publish`). Nothing changes on existing routes in this batch.
|
||||
- **Schema migrations**: `env/db/04_detection_classes.sql` and `env/db/05_resources.sql` added; both use `create table if not exists` and idempotent `grant`s, so they are safe to re-run. `e2e/db-init/00_run_all.sh` updated to apply both during the test-DB bootstrap.
|
||||
- **DI**: `AddScoped<IDetectionClassService, DetectionClassService>()` and `AddScoped<IResourceUpdateService, ResourceUpdateService>()` added next to the existing `IUserService` registration in `Program.cs`. `AddValidatorsFromAssemblyContaining<RegisterUserValidator>()` (already present) auto-discovers the new validators in `Azaion.Common`.
|
||||
- **`IDbFactory.RunAdmin<T>(...)`**: Overload added to support write-and-return patterns (used by AZ-513's `Create` returning the new id, AZ-196's `RegisterDevice` returning the credentials, and AZ-183's parts of the publish/lookup paths). Non-breaking addition.
|
||||
- **Encryption-at-rest for AZ-183**: Per-resource `encryption_key` column is AES-256-CBC encrypted with a master key from `ResourcesConfig.EncryptionMasterKey`. The wire response carries plaintext (the device needs it to decrypt the artifact). Master key for tests is provided via `docker-compose.test.yml`; production must override via `ResourcesConfig__EncryptionMasterKey` env var.
|
||||
- **AZ-197 not in this batch**: AZ-197 (remove hardware ID binding) was originally cross-workspace (Admin API + Loader). User clarified 2026-05-13 that the Loader is architecturally retired (Scenario X, see `suite/_docs/_repo-config.yaml` `unresolved:loader-retirement-arch-doc`) and devices ship as secured Jetsons with fTPM or via SaaS. The AZ-197 spec was rewritten to be admin-only; the destructive cleanup is isolated into batch 6 (cycle 1, batch 2 of 2) for focused review.
|
||||
- **`module-layout.md` backfill**: Created earlier in this `/autodev` step to satisfy the implement skill's File Ownership prerequisite. The `_docs/` artifact set predates the Step 1.5 module-layout addition; this is a backfill, not a fresh decompose run.
|
||||
|
||||
## Next Batch
|
||||
|
||||
Batch 6 (cycle 1, batch 2 of 2): AZ-197 (remove hardware ID binding from admin/ + e2e cleanup).
|
||||
@@ -0,0 +1,64 @@
|
||||
# Code Review Report
|
||||
|
||||
**Batch**: 5 (cycle 1, batch 1 of 2)
|
||||
**Tasks**: AZ-513, AZ-196, AZ-183
|
||||
**Date**: 2026-05-13
|
||||
**Verdict**: PASS_WITH_WARNINGS
|
||||
|
||||
## Summary
|
||||
|
||||
All three additive tasks (Detection Classes CRUD, device registration, fleet OTA Resources) build clean (`dotnet build` 0 warnings, 0 errors against both `Azaion.AdminApi.sln` and `e2e/Azaion.E2E/Azaion.E2E.csproj`), respect the `Azaion.AdminApi → Azaion.Services → Azaion.Common` layering recorded in `_docs/02_document/module-layout.md`, and follow the existing `IUserService` / `Program.cs` / `AzaionDbSchemaHolder` patterns. AC coverage is verified via new e2e tests in `e2e/Azaion.E2E/Tests/` for every admin-side AC. No Critical or High findings; the four Low / Medium findings below are non-blocking and tracked for follow-up.
|
||||
|
||||
## Findings
|
||||
|
||||
| # | Severity | Category | File:Line | Title |
|
||||
|---|----------|-----------------|--------------------------------------------------------|-------|
|
||||
| 1 | Medium | Bug | `Azaion.Services/UserService.cs` (RegisterDevice) | Race condition on sequential serial assignment |
|
||||
| 2 | Low | Maintainability | `Azaion.Services/ResourceUpdateService.cs` (Publish) | No uniqueness on `(arch, stage, name, version)` rows |
|
||||
| 3 | Low | Maintainability | `Azaion.Services/ResourceUpdateService.cs` (Encrypt) | Master-key rotation not supported (no key-version column) |
|
||||
| 4 | Low | Maintainability | `Azaion.AdminApi/appsettings.json` | `EncryptionMasterKey` ships empty by default |
|
||||
|
||||
### Finding Details
|
||||
|
||||
**F1: Race condition on sequential serial assignment** (Medium / Bug)
|
||||
- Location: `Azaion.Services/UserService.cs` → `RegisterDevice`
|
||||
- Description: Two concurrent `POST /devices` calls can both read the same most-recent `CompanionPC` user, compute the same next number, and both insert. The `users.email` column has no DB-level unique constraint (per `_docs/02_document/data_model.md` § Observations), so the second insert succeeds and creates two users with the same email.
|
||||
- Suggestion: For the AZ-196 use case (Jetson manufacturing — sequential by design), this is currently low-impact. Long-term mitigations: (a) add a unique constraint on `users.email` and retry on conflict, (b) wrap the read+insert in a `BEGIN; SELECT ... FOR UPDATE; INSERT; COMMIT;` block via `db.BeginTransactionAsync(IsolationLevel.Serializable)`, or (c) drop sequential numbering and use a Guid suffix. Track as a follow-up; out of scope for this 2-pt ticket per spec.
|
||||
- Task: AZ-196
|
||||
|
||||
**F2: No uniqueness on `(arch, stage, name, version)` rows** (Low / Maintainability)
|
||||
- Location: `Azaion.Services/ResourceUpdateService.cs` → `Publish`; `env/db/05_resources.sql`
|
||||
- Description: A re-publish of the same `(architecture, dev_stage, resource_name, version)` tuple will insert a duplicate row. `LoadLatest`'s `OrderByDescending(r => r.Version)` still picks one of them (non-deterministically among equal versions), so device behavior is correct, but the table grows unbounded under repeated re-publishes.
|
||||
- Suggestion: Add a unique constraint `(architecture, dev_stage, resource_name, version)` in a follow-up migration and decide on `INSERT ... ON CONFLICT DO NOTHING` vs `DO UPDATE` semantics. Out of scope for AZ-183's 3-pt budget.
|
||||
- Task: AZ-183
|
||||
|
||||
**F3: Master-key rotation not supported** (Low / Maintainability)
|
||||
- Location: `Azaion.Services/ResourceUpdateService.cs` → `ResourceColumnEncryption`
|
||||
- Description: The per-resource `encryption_key` column is AES-encrypted with a single static master key from `ResourcesConfig.EncryptionMasterKey`. Rotating the master key would render all existing rows undecryptable. There is no key-version column or fallback list.
|
||||
- Suggestion: For an OTA system whose master-key compromise blast radius is "every device-side decryption breaks", a future ticket should add `(key_version_id, ciphertext)` storage and a `Dictionary<int, string> activeKeys` with a `currentKeyVersion`. Out of scope here.
|
||||
- Task: AZ-183
|
||||
|
||||
**F4: `EncryptionMasterKey` ships empty by default** (Low / Maintainability)
|
||||
- Location: `Azaion.AdminApi/appsettings.json`
|
||||
- Description: Default value is `""`. The service throws `InvalidOperationException` on first call to `GetUpdate` / `Publish` if the env var override is missing. This is intentional (no insecure default) but means a fresh `dotnet run` of the admin API in development will surprise the developer.
|
||||
- Suggestion: Either (a) keep the empty default and document the env var in the README, or (b) ship a clearly-marked dev-only key in `appsettings.Development.json`. The test runner is already wired up via `docker-compose.test.yml`. Pick one and document.
|
||||
- Task: AZ-183
|
||||
|
||||
## Phase results
|
||||
|
||||
- **Phase 1 (Context)**: 3 task specs read; project restrictions/solution unchanged.
|
||||
- **Phase 2 (Spec compliance)**: AZ-513 ACs 1–9 covered by `DetectionClassesTests.cs`; AC-10 is cross-workspace (UI). AZ-196 ACs 1–5 covered by `DeviceRegistrationTests.cs` (AC-1 verifies the format `azj-NNNN`; the literal "0000" assertion is intentionally relaxed because the test DB may carry CompanionPC users from earlier runs — sequential AC-2 is the meaningful guarantee). AZ-183 ACs 1, 2, 3, 5 covered by `ResourceUpdateTests.cs`; AC-4 ("memory cache avoids repeated DB queries") is a perf characteristic not directly assertable via HTTP and is verified by inspection of `ResourceUpdateService.GetUpdate` (the `cache.GetFromCacheAsync` wraps `LoadLatest`).
|
||||
- **Phase 3 (Code quality)**: SRP respected (`DetectionClassService` separated from `UserService`; `ResourceUpdateService` separated from the file-storage `ResourcesService`). No methods > 50 LoC. No bare catches. Naming consistent with existing `I*Service` / `*Request` / `*Response` conventions.
|
||||
- **Phase 4 (Security quick-scan)**: No SQL string interpolation (linq2db parameterizes). No command injection. No hardcoded secrets in production code paths — the only literal key is in `docker-compose.test.yml` and is explicitly labeled "do-not-use-in-prod". Input validation via FluentValidation on every DTO. Plaintext password is returned by `POST /devices` per AZ-196 spec (intentional, embedded in the device.conf by provisioning).
|
||||
- **Phase 5 (Performance scan)**: `ResourceUpdateService.LoadLatest` reads all rows for `(arch, stage)` then group-bys in memory — acceptable given `cache.GetFromCacheAsync` (default 4-hour TTL) and the small per-(arch,stage) row count expected for fleet OTA. No N+1. All DB calls async.
|
||||
- **Phase 6 (Cross-task consistency)**: All three tasks add a single `MapXxx` block in `Program.cs`, register one `IService` in DI, and use the same FluentValidation + `Results.ValidationProblem` pattern. New `IDbFactory.RunAdmin<T>(...)` overload added by AZ-513 is reused by AZ-196 and AZ-183 — shared abstraction is genuine, not duplicated.
|
||||
- **Phase 7 (Architecture compliance)**: All imports respect the `Azaion.AdminApi → Azaion.Services → Azaion.Common` layering and the `Azaion.Test` / `e2e/Azaion.E2E` test-only boundaries. No new cross-component imports of internal symbols. No new cyclic module dependencies. `_docs/02_document/module-layout.md` was created earlier in this `/autodev` step to satisfy the implement skill's prerequisite — no edit to it in this batch.
|
||||
|
||||
## Verdict logic
|
||||
|
||||
- 0 Critical, 0 High → not FAIL
|
||||
- 1 Medium + 3 Low → PASS_WITH_WARNINGS
|
||||
|
||||
## Action
|
||||
|
||||
Proceed to commit. The four findings are tracked here and should be revisited as separate tickets when their respective contexts (manufacturing throughput, fleet rollout cadence, key-rotation policy, dev-onboarding ergonomics) warrant.
|
||||
@@ -6,8 +6,9 @@ step: 10
|
||||
name: Implement
|
||||
status: in_progress
|
||||
sub_step:
|
||||
phase: 0
|
||||
name: awaiting-invocation
|
||||
detail: ""
|
||||
phase: 6
|
||||
name: implement-tasks-sequentially
|
||||
detail: "batch 1 / step 9 — code-review"
|
||||
retry_count: 0
|
||||
cycle: 1
|
||||
tracker: jira
|
||||
|
||||
Reference in New Issue
Block a user