DEC-W02-ASYNC — Bounded Product Freeze (Student Import Job)
Mode: Server /home/scola/odoo
Approval: APPROVED_BY_REQUESTING_USER_CONVERSATION (2026-08-29)
Scope: Subset of DEC-008 (master-data) limited to scola.student.import.job async path only
Format: Same bounded-decision pattern as T4-DEC-W01-W02-bounded-freezes.md
Explicit boundary: This freeze covers import job semantics only — not MD-01–MD-03 full master-data ownership, not W19 sync, not admission config.
RT-W02-IDM-01 — Async import idempotency
SC-CORE status: PASS — async idempotency harness W02-ASYNC-IDM-DUPLICATE-KEY (2026-08-29)
| Aspect |
V1 bounded decision (async path) |
| Idempotency key |
Client-supplied idempotency_key + company_id unique (student_import_idempotency_company_uniq) |
| Duplicate enqueue |
Returns existing job record; no second job created (enqueue() → existing, True) |
| Concurrent duplicate request |
Same key → same job_id; stable public_result() |
| Timeout retry |
Client may poll same job_id; re-submit with same key returns existing job |
| Attribution |
requested_by immutable on job; audit on create |
| Harness proof |
W02-ASYNC-IDM-DUPLICATE-KEY, concurrent enqueue cases |
Out of scope: Cross-company key collision (keys scoped per company); file-hash dedupe without explicit key = NOT RUN.
RT-W02-REC-01 — Async import recovery
SC-CORE status: PASS — partial failure + stuck recovery harness (2026-08-29)
| Aspect |
V1 bounded decision (async path) |
| Job states |
queued → running → done | failed |
| Fault stages |
Row persist, parent link, batch assign — ROW_ATOMIC per row within job (extends manual ROW_ATOMIC policy) |
| Partial failure |
Job completes failed or done with error_count > 0; accepted rows remain committed |
| Resume |
No automatic resume V1 — client re-enqueues with new idempotency_key for unprocessed rows only (manual operator path) |
| Cron recovery |
Stuck running → reset to queued or mark failed after timeout (engineering implements; bounded: max 1 retry) |
| Reversal |
No bulk undo V1 — operator deactivates/archives created records individually; job result documents created IDs |
| Harness proof |
Fault injection at link/batch stage; partial commit visible; error report scoped |
Error report redaction
| Aspect |
V1 bounded decision |
| Download scope |
students.manage + same company as job; job owner or school_admin |
| Redaction |
No cross-row PII beyond failing row; no foreign company identifiers |
| Content |
Row index, field, safe error code/message; no stack trace to client |
| Storage |
result JSON on job record; downloadable via status poll endpoint |
| Harness proof |
Error report denied to viewer/teacher; owner download PASS |
Concurrent job policy
| Aspect |
V1 bounded decision |
| Same company |
One active job (queued or running) per company at a time — second enqueue returns 409 or queues after first completes (Product selects; recommend 409 explicit) |
| Cross-user |
Same rule — company-scoped, not user-scoped |
| Harness proof |
Concurrent enqueue second job denied or serialized |
FE contract (STAB-023 alignment)
| Aspect |
V1 bounded decision |
| Progress |
Poll public_result() — progress, processed, success_count, error_count |
| Retry |
New upload requires new idempotency_key (client-generated UUID) |
| Error download |
Available when state in (done, failed) and error_count > 0 |
| UI |
UploadSiswa.vue — progress/retry/error download |
Explicit NOT RUN (non-claim)
| Item |
Status |
Reason |
| Full DEC-008 master-data |
Out of import-job subset |
MD-01–MD-03 separate Product gate |
| Automatic job resume |
NOT RUN V1 |
Manual re-enqueue with new key |
| Bulk reversal API |
NOT RUN V1 |
Individual archive/deactivate only |
| W16 / Profile denominator |
Separate tracks |
See Post-SCORE program plan |
Certification denominator summary
| Workstream |
Harness |
Target |
Matrix rows |
| W02 async |
w02_runtime_certify.py extended or w02_async_import_certify.py |
IDM+REC PASS |
§5.2 RT-W02-IDM-01, RT-W02-REC-01 |
| W02 manual (existing) |
w02_runtime_certify.py |
33/33 PASS (unchanged) |
§5.2 other rows — SC-CORE claim preserved |
| W05 regression |
w05_runtime_certify.py |
16/16 PASS |
Guard after async extend |
Sign-off record
Product bounded options above approved via conversational sign-off in Post-SCORE program execution (2026-08-29 — APPROVED_BY_REQUESTING_USER_CONVERSATION). ASYNC-1 engineering proceeded 2026-08-29; harness evidence in T3-W02-evidence/.
References