DEC-W16 — Bounded Product Freezes (Canonical News V1)
Mode: Server /home/scola/odoo
Approval: APPROVED_BY_REQUESTING_USER_CONVERSATION (2026-08-29)
Scope: Minimum product decisions to unblock §5.3 BLOCKED rows without new feature scope
Format: Same bounded-decision pattern as T4-DEC-W01-W02-bounded-freezes.md
RT-W16-NEG-01 — Capability / approval matrix
Blockers: DEC-003 (RBAC scope), DEC-004 (maker-checker / approval roles)
| Aspect |
V1 bounded decision |
| Create / edit draft |
news.author capability — assigned author or school_admin |
| Submit for review |
Author only on own draft |
| Approve / reject |
news.approve — distinct from author (no self-approval on publish path) |
| Publish |
news.publish — may coincide with approver role in small schools; audit records actor |
| Archive / unpublish |
news.publish or school_admin; reversal reason required (see STA) |
| Read-only leadership / reader |
Denied create/approve/publish/archive; direct API denied; record/outbox unchanged |
| Harness proof |
W16-NEG-* denied cases; capability bypass RPC denied |
RT-W16-STA-01 — Publication state machine / reversal
Blocker: DEC-007 (state transition / reversal policy)
| Aspect |
V1 bounded decision |
| States |
draft → submitted → approved → published → archived; rejected returns to editable draft |
| Invalid transition |
Denied atomically; history immutable (append-only audit) |
| Reversal after publish |
Unpublish → archived only (no silent delete); correction = new revision or edit-before-republish per Product |
| Late transition |
Publish window enforced server-side; late publish denied with audit reason |
| Self-approval |
Denied on publish path when author = approver (configurable override = out of V1) |
| Harness proof |
W16-STA-* transition matrix; repeated/invalid transition denied |
RT-W16-REC-01 — Notification / delivery recovery
Blocker: DEC-010 (notification semantics, retry, dedupe)
| Aspect |
V1 bounded decision |
| Authoritative record |
Canonical scola.news row remains source of truth after publish |
| Delivery failure |
Outbox/notification failure visible to publisher (status field or job log) |
| Retry |
Manual or cron retry deduped — one notification effect per reader per publication event |
| Unpublish / archive |
Stops future delivery; does not retract already-delivered push (bounded V1 — in-app read state updated) |
| Harness proof |
Fault injection after publish; canonical record unchanged; retry creates no duplicate |
RT-W16-XRP-01 — Reader propagation
Blocker: DEC-010 (notification behavior to target/non-target readers)
| Aspect |
V1 bounded decision |
| Target readers |
Receive publication once per audience projection; correction/archive updates in-app feed |
| Non-target |
Never receive notification or sensitive audience metadata |
| Guessed news ID |
Denied read outside audience scope |
| Dedupe |
Same reader + same publication event = one in-app entry + one push (if enabled) |
| Harness proof |
Target/non-target student/parent/teacher fixtures; propagation once; non-target zero leak |
RT-W16-XMD-01 — Legacy migration / cross-module integration
Blockers: DEC-011 (legacy data policy), STAB-033 (duplicate canonical/legacy publication)
| Aspect |
V1 bounded decision |
| Writable source |
scola.news only — legacy announcement write API/menu absent or 403 |
| Legacy read |
Historical announcement rows read-only in portal; deep links redirect or show migrated banner |
| Migration |
One-time migration maps legacy ID → canonical ID; no duplicate notification on migration run |
| Calendar / notification shell |
Declared link preserves canonical ID; no second write path |
| Harness proof |
Legacy direct API denied; migrated history readable; canonical publish creates single effect |
Blockers: STAB-033, DEC-011, IA-010
| Aspect |
V1 bounded decision |
| Create / publish |
Exactly one canonical menu/route/CTA (communication app) |
| Legacy write |
Menu leaf and route absent or fail-closed redirect |
| Reader UI |
Valid empty/loading/error states; responsive mobile/desktop |
| Deep links |
Legacy URLs redirect to canonical read view or safe unsupported state |
| Harness proof |
check:core-nav-ux communication routes + spot crawl; legacy write menu absent |
RT-W16-VAL-01 — Invalid payload / window
| Aspect |
V1 bounded decision |
| Invalid window / missing target |
Rejected atomically; zero partial row |
| Harness proof |
W16-VAL-INVALID-PAYLOAD |
RT-W16-VAL-02 — Optional summary (no body snippet)
Patch: BE 7ffb0ad — scola.news.summary optional on create/write.
| Aspect |
V1 bounded decision |
| Omitted / empty summary |
Stays empty — no auto-snippet from body_html |
| Explicit summary |
Preserved verbatim |
| Portal/list payload |
Empty summary omitted or false; body unchanged |
| Harness proof |
W16-VAL-OPTIONAL-SUMMARY on Golden :8090 |
Supporting rows (currently NOT RUN — engineering defaults)
These rows unblock at W16-2/W16-3 without additional Product gate beyond charter approval:
RT-W16-POS-01 — Positive publish path
| Aspect |
V1 bounded decision |
| Flow |
Author creates → submit → approver approves → publisher publishes → intended reader sees once |
| Audit |
Actors and state transitions recorded |
| Harness proof |
W16-POS-* end-to-end on GT-TXN-W16-NEWS fixtures |
RT-W16-IDM-01 — Publish idempotency
| Aspect |
V1 bounded decision |
| Concurrent / repeated publish |
One publication/circular/notification effect; stable audit |
| Cron / scheduler |
Idempotent outbox dispatch |
| Harness proof |
GT-TXN-RETRY-IDEMPOTENT duplicate publish/cron cases |
Explicit NOT RUN (non-claim)
| Item |
Status |
Reason |
UAT PROMOTE_UAT |
Out of W16 track |
Gelombang terpisah — charter §1 |
| Production promotion |
Not authorized |
Immutable CERTIFIED manifest required |
| Full DEC-010 enterprise notification bus |
Out of V1 bounded |
In-app + bounded outbox only unless Product expands |
Certification denominator summary
| Workstream |
Harness |
Target |
Matrix rows |
| W16 |
w16_runtime_certify.py (TBD) |
12/12 PASS |
§5.3 all 12 rows |
| E1.2 regression |
e12_security_matrix.py |
29/29 PASS |
No SC-CORE regression |
Sign-off record
| Date |
Approver |
Decision |
Scope |
| 2026-08-29 |
Requesting user (Post-SCORE Build/Lanjutkan) |
APPROVED — all bounded options in this document as written |
W16-1 unblocks W16-2 engineering; does not authorize production promotion or UAT wave |
Product bounded options signed 2026-08-29 via conversational approval in Post-SCORE program execution (APPROVED_BY_REQUESTING_USER_CONVERSATION).