|
1447 | 1447 | "history": [ |
1448 | 1448 | { "revision": 1, "date": "2026-08-30", "change": "initial — the inbox's keyboard surface (documented in the page's own header and advertised by its hint bar) had no checklist coverage; the load-bearing halves are that r/a land the same server transition as the buttons and that quick-decidability gates hotkeys off rows whose decisions require typed outputs", "ref": "#sweep-2026-08-30" } |
1449 | 1449 | ] |
| 1450 | + }, |
| 1451 | + { |
| 1452 | + "id": "approvals.request-page-reply-and-reader-visibility", |
| 1453 | + "title": "Approval requests on v18: the request record page serves record:approval_decision and a Reply action that lands in its timeline, `enable.approvalsVisibleToReaders` lets a plain record reader see the record's requests read-only (and only then), the generic /data door serves request rows by approvals visibility, and titles shown to a reader use only what that reader may read", |
| 1454 | + "since": "v18", |
| 1455 | + "status": "active", |
| 1456 | + "revision": 1, |
| 1457 | + "priority": "P1", |
| 1458 | + "surface": "mixed", |
| 1459 | + "personas": [ |
| 1460 | + "seeded admin (admin@objectos.ai / admin123) — the Default Organization owner and platform admin on a fresh boot", |
| 1461 | + "org member (a second sign-up on the same boot — joins the Default Organization as `member`, not platform admin)" |
| 1462 | + ], |
| 1463 | + "fixtures": { |
| 1464 | + "app": "showcase", |
| 1465 | + "requires": [ |
| 1466 | + "a fresh boot of the showcase: `pnpm dev -- --fresh -p PORT --seed-admin` (ephemeral DB; the seeded admin is printed)", |
| 1467 | + "a pending showcase approval request the member is NOT an approver on", |
| 1468 | + "for the reader leg: a scratch object (or showcase object via the scratch app) with enable.approvalsVisibleToReaders:true" |
| 1469 | + ], |
| 1470 | + "knownGaps": [ |
| 1471 | + "the console clause needs the vendored console — blocked(environment) while the .objectui-sha pin does not build against current spec (see records-forms.v18-semantic-defaults)" |
| 1472 | + ] |
| 1473 | + }, |
| 1474 | + "steps": [ |
| 1475 | + "GET /api/v1/meta/page/sys_approval_request_detail and find record:approval_decision", |
| 1476 | + "as the pending approver POST /api/v1/approvals/requests/ID/comment {body}; read the timeline", |
| 1477 | + "as the member (non-participant) GET /api/v1/data/sys_approval_request/ID and list with a total", |
| 1478 | + "flip approvalsVisibleToReaders on the scratch object; as a plain reader list that record's requests; flip it off and repeat without restart" |
| 1479 | + ], |
| 1480 | + "acceptance": [ |
| 1481 | + { |
| 1482 | + "clause": "request page, reply, reader opt-in, generic-door read gate and reader-scoped titles — the permanent pins pass at the run subject sha (RUNNER rule 6: cite their output, never re-derive by hand)", |
| 1483 | + "oracle": "test", |
| 1484 | + "verify": "run each file named in automated.ref with its package's vitest (`pnpm --filter PKG exec vitest run --maxWorkers=2 FILE`, never through a bare `--`); every named file reports ≥1 test and 0 failed. A file that reports 0 tests or is not found is NOT a pass — it is a stale ref, fix the item", |
| 1485 | + "evidence": "the vitest summary line per pin file, with the package name and the subject sha" |
| 1486 | + }, |
| 1487 | + { |
| 1488 | + "clause": "the request page carries record:approval_decision and the reply lands in the timeline (pending approver or submitter only)", |
| 1489 | + "oracle": "api", |
| 1490 | + "verify": "page body + timeline read", |
| 1491 | + "evidence": "excerpts" |
| 1492 | + }, |
| 1493 | + { |
| 1494 | + "clause": "a non-participant's by-id read on /data/sys_approval_request → 404 and list totals exclude it", |
| 1495 | + "oracle": "api", |
| 1496 | + "verify": "status + total", |
| 1497 | + "evidence": "answers" |
| 1498 | + }, |
| 1499 | + { |
| 1500 | + "clause": "the reader sees requests read-only with no actions only while the flag is on; the inbox is not widened", |
| 1501 | + "oracle": "api", |
| 1502 | + "verify": "list per flag state", |
| 1503 | + "evidence": "two lists" |
| 1504 | + }, |
| 1505 | + { |
| 1506 | + "clause": "the console decision panel renders on the request page", |
| 1507 | + "oracle": "screenshot", |
| 1508 | + "verify": "request page after load", |
| 1509 | + "evidence": "one-line description" |
| 1510 | + } |
| 1511 | + ], |
| 1512 | + "traps": [ |
| 1513 | + "wrong-persona", |
| 1514 | + "stale-console-bundle" |
| 1515 | + ], |
| 1516 | + "automated": { |
| 1517 | + "kind": "unit", |
| 1518 | + "ref": "packages/plugins/plugin-approvals/src/sys-approval-request-page.test.ts + packages/spec/src/ui/component-record-approval-decision-22472.test.ts + packages/plugins/plugin-approvals/src/record-reader-opt-in.integration.test.ts + packages/plugins/plugin-approvals/src/request-child-read-gate.integration.test.ts + packages/plugins/plugin-approvals/src/subject-title-reader-fls.integration.test.ts" |
| 1519 | + }, |
| 1520 | + "source": [ |
| 1521 | + "packages/plugins/plugin-approvals/src/sys-approval-request.page.ts", |
| 1522 | + "packages/plugins/plugin-approvals/src/request-read-gate.ts#bindRequestReadGate", |
| 1523 | + "packages/plugins/plugin-approvals/src/approval-service.ts", |
| 1524 | + "v18 changesets (.changeset/pre/, consumed into 18.0.0-next.*): 22472-spec-record-approval-decision, 22473-approval-request-page, 22560-platform-objects-approvals-visible-to-readers-form-row, 22560-plugin-approvals-declared-record-reader-tier, 22560-spec-approvals-visible-to-readers, 22559-approval-request-read-gate, 22589-approval-sibling-read-gates, 23594-subject-title-reader-fls, 23618-approval-title-family-served-fields, 23637-lookup-target-title-row-access" |
| 1525 | + ], |
| 1526 | + "history": [ |
| 1527 | + { |
| 1528 | + "revision": 1, |
| 1529 | + "date": "2026-10-16", |
| 1530 | + "change": "initial — authored from the v18 line (18.0.0-next.*) delta: the capability landed on the v18 pre-release line and the ledger carried no `since: \"v18\"` item for it", |
| 1531 | + "ref": "#23879" |
| 1532 | + } |
| 1533 | + ] |
| 1534 | + }, |
| 1535 | + { |
| 1536 | + "id": "approvals.act-door-and-admin-rescue-slate", |
| 1537 | + "title": "Approvals on v18: the email action door /approvals/act works through the dispatcher exactly as the self-hosted mount (GET renders, POST redeems, PUT 405 Allow: GET, POST, a dead link a 200 page, a policy-held session not 403'd before the token), and an approval over an unstaffed position opens on the org administrators as ordinary approvers", |
| 1538 | + "since": "v18", |
| 1539 | + "status": "active", |
| 1540 | + "revision": 1, |
| 1541 | + "priority": "P1", |
| 1542 | + "surface": "api", |
| 1543 | + "personas": [ |
| 1544 | + "seeded admin (admin@objectos.ai / admin123) — the Default Organization owner and platform admin on a fresh boot", |
| 1545 | + "org member (a second sign-up on the same boot — joins the Default Organization as `member`, not platform admin)" |
| 1546 | + ], |
| 1547 | + "fixtures": { |
| 1548 | + "app": "showcase", |
| 1549 | + "requires": [ |
| 1550 | + "a fresh boot of the showcase: `pnpm dev -- --fresh -p PORT --seed-admin` (ephemeral DB; the seeded admin is printed)", |
| 1551 | + "an approval email action token (dev mail transport capture) for a pending request", |
| 1552 | + "an approval process whose approver is a position nobody holds (scratch process, default onEmptyApprovers)" |
| 1553 | + ] |
| 1554 | + }, |
| 1555 | + "steps": [ |
| 1556 | + "GET /api/v1/approvals/act?token=T; POST the same; PUT the same; GET with a consumed token", |
| 1557 | + "submit a record into the unstaffed process; as the org admin GET /api/v1/approvals/requests (My Pending); decide it" |
| 1558 | + ], |
| 1559 | + "acceptance": [ |
| 1560 | + { |
| 1561 | + "clause": "the dispatcher act door and the admin_rescue slate — the permanent pins pass at the run subject sha (RUNNER rule 6: cite their output, never re-derive by hand)", |
| 1562 | + "oracle": "test", |
| 1563 | + "verify": "run each file named in automated.ref with its package's vitest (`pnpm --filter PKG exec vitest run --maxWorkers=2 FILE`, never through a bare `--`); every named file reports ≥1 test and 0 failed. A file that reports 0 tests or is not found is NOT a pass — it is a stale ref, fix the item", |
| 1564 | + "evidence": "the vitest summary line per pin file, with the package name and the subject sha" |
| 1565 | + }, |
| 1566 | + { |
| 1567 | + "clause": "GET renders the action page, POST redeems, PUT → 405 with Allow: GET, POST, a dead token → a 200 page (not an error envelope)", |
| 1568 | + "oracle": "api", |
| 1569 | + "verify": "status + headers per verb", |
| 1570 | + "evidence": "four lines" |
| 1571 | + }, |
| 1572 | + { |
| 1573 | + "clause": "the unstaffed request appears in each org admin's pending list and the decision is recorded via_override:false", |
| 1574 | + "oracle": "api", |
| 1575 | + "verify": "pending list + decision record", |
| 1576 | + "evidence": "excerpts" |
| 1577 | + } |
| 1578 | + ], |
| 1579 | + "automated": { |
| 1580 | + "kind": "dogfood", |
| 1581 | + "ref": "packages/runtime/src/domains/approvals-act.test.ts + packages/plugins/plugin-approvals/src/action-page-member.integration.test.ts + packages/plugins/plugin-approvals/src/admin-rescue-named-slate.integration.test.ts + packages/qa/dogfood/test/approval-admin-rescue-slate.dogfood.test.ts" |
| 1582 | + }, |
| 1583 | + "source": [ |
| 1584 | + "packages/runtime/src/domains/approvals.ts", |
| 1585 | + "packages/core/src/security/auth-gate.ts", |
| 1586 | + "packages/plugins/plugin-approvals/src/approval-service.ts", |
| 1587 | + "v18 changesets (.changeset/pre/, consumed into 18.0.0-next.*): 22575-spec-approvals-action-page-member, 22577-approvals-act-allowlist, 22578-approvals-action-page-member, 22824-admin-rescue-named-slate" |
| 1588 | + ], |
| 1589 | + "history": [ |
| 1590 | + { |
| 1591 | + "revision": 1, |
| 1592 | + "date": "2026-10-16", |
| 1593 | + "change": "initial — authored from the v18 line (18.0.0-next.*) delta: the capability landed on the v18 pre-release line and the ledger carried no `since: \"v18\"` item for it; approvals.approver-resolution-matrix still says admin_rescue is decidable only via the privileged override — stale against 22824 (reported, not edited here)", |
| 1594 | + "ref": "#23879" |
| 1595 | + } |
| 1596 | + ] |
1450 | 1597 | } |
1451 | 1598 | ] |
1452 | 1599 | } |
0 commit comments