Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
299f666
test(access): define short-lived grant domain contract
seonghobae Aug 15, 2026
bde23d4
test(access): register grant contract in canonical coverage
seonghobae Aug 15, 2026
b5af722
test(access): lock grant module into coverage producer
seonghobae Aug 15, 2026
06f8c5f
test(access): cover fail-closed grant edge paths
seonghobae Aug 15, 2026
8c15131
test(access): exercise grant edge coverage
seonghobae Aug 15, 2026
801c2f2
feat(access): add opaque short-lived grant domain
seonghobae Aug 15, 2026
50cab29
docs(access): record short-lived grant trust boundary
seonghobae Aug 15, 2026
962e9da
docs(changelog): record access-grant domain foundation
seonghobae Aug 15, 2026
074cf17
test(access): require grant identifiers independent of secret hash
seonghobae Aug 15, 2026
baaae4e
test(access): cover independent grant-id entropy contract
seonghobae Aug 15, 2026
418afcc
fix(access): decouple audit grant ids from secret hashes
seonghobae Aug 15, 2026
ef70c32
docs(access): separate correlation ids from token hashes
seonghobae Aug 15, 2026
d0b2d33
test(coverage): lock access-grant edge cases into c8
seonghobae Aug 15, 2026
f590a66
test(access): reproduce audit and membership race failures
seonghobae Aug 15, 2026
c3a26b8
fix(access): close audit and membership race windows
seonghobae Aug 15, 2026
bc00fc0
docs(access): define race-safe membership and audit durability
seonghobae Aug 15, 2026
8cf44c0
test(access): reject unusable membership versions before consume
seonghobae Aug 15, 2026
7c91b4d
fix(access): require usable membership version before consume
seonghobae Aug 15, 2026
28908e9
test(access): align harness with membership-version consume contract
seonghobae Aug 15, 2026
c86c878
test(calendar): define durable subscription lifecycle contract
seonghobae Aug 15, 2026
1210d52
feat(calendar): add reusable scoped subscription domain
seonghobae Aug 15, 2026
1bb891b
test(calendar): cover subscription domain failure boundaries
seonghobae Aug 15, 2026
1853aae
test(calendar): register subscription coverage cases
seonghobae Aug 15, 2026
ad4ca00
test(coverage): lock calendar subscription evidence
seonghobae Aug 15, 2026
15a9d40
docs(calendar): record reusable credential security boundary
seonghobae Aug 15, 2026
927f90c
docs(changelog): record calendar subscription domain
seonghobae Aug 15, 2026
3f6553b
docs(calendar): trace Figma interaction contract
seonghobae Aug 15, 2026
cf12559
docs(changelog): trace calendar interaction design
seonghobae Aug 15, 2026
8ada3b5
merge(access): reconcile grant domain with protected develop
seonghobae Aug 16, 2026
1c9d5cd
fix(changelog): preserve shipped performance wording
seonghobae Aug 16, 2026
5cc9c6a
test(calendar): define durable SQLite subscription contract
seonghobae Aug 16, 2026
f2bd18d
test(calendar): register SQLite persistence regression
seonghobae Aug 16, 2026
01ed37d
test(calendar): lock SQLite coverage registration
seonghobae Aug 16, 2026
7f66768
feat(calendar): add atomic SQLite subscription persistence
seonghobae Aug 16, 2026
f4a2e75
docs(calendar): trace durable SQLite subscription persistence
seonghobae Aug 16, 2026
6b03544
docs(calendar): record active SQLite persistence slice
seonghobae Aug 16, 2026
d725de7
test(calendar): cover SQLite fail-closed edge transitions
seonghobae Aug 16, 2026
6f04735
test(calendar): expose management revocation race
seonghobae Aug 16, 2026
517dcaf
test(calendar): run management race regression
seonghobae Aug 16, 2026
32860e2
fix(calendar): close management authorization races
seonghobae Aug 16, 2026
25162f0
test(calendar): expose rotation membership race
seonghobae Aug 16, 2026
09012da
fix(calendar): preserve rotation not-found boundary
seonghobae Aug 16, 2026
ccef905
docs(calendar): correct SQLite scenario evidence
seonghobae Aug 16, 2026
454d12e
test(calendar): expose savepoint cleanup masking
seonghobae Aug 16, 2026
eacc73b
test(calendar): expose rollback cleanup masking
seonghobae Aug 16, 2026
26b7346
fix(calendar): preserve causal savepoint errors
seonghobae Aug 16, 2026
ae5e6db
test(calendar): close SQLite integrity coverage gaps
seonghobae Aug 16, 2026
e59070d
merge: reconcile calendar domain with access-grant parent
seonghobae Aug 16, 2026
76fa467
merge: reconcile SQLite subscriptions with calendar parent
seonghobae Aug 16, 2026
7246089
Merge branch 'develop' into feat/access-grant-domain-413
opencode-agent[bot] Aug 16, 2026
a2ce027
merge(calendar): reconcile subscription domain with current access-gr…
seonghobae Aug 16, 2026
03b0d91
fix(calendar): bind reusable secrets to issuance membership epoch
cursoragent Aug 16, 2026
6885434
test(calendar): cover issuance epoch persistence contract
seonghobae Aug 16, 2026
2ee8706
test(calendar): run issuance epoch SQLite regressions
seonghobae Aug 16, 2026
63e8898
fix(calendar): persist purpose and issuance epoch semantics
seonghobae Aug 16, 2026
db3fd1e
fix(calendar): bind omitted purpose to calendar_read
cursoragent Aug 16, 2026
878979b
chore(calendar): reconcile SQLite adapter with issuance-epoch parent
seonghobae Aug 16, 2026
0117737
fix(calendar): restore issuance-epoch parent tree before adapter overlay
seonghobae Aug 16, 2026
0df9c2a
docs(calendar): reconcile adapter architecture onto issuance-epoch pa…
seonghobae Aug 16, 2026
3708728
docs(calendar): reconcile SQLite persistence changelog
seonghobae Aug 16, 2026
7db97fd
test(calendar): run SQLite adapter under unit and coverage suites
seonghobae Aug 16, 2026
e49b967
test(calendar): require SQLite coverage registration
seonghobae Aug 16, 2026
efc81c1
docs(calendar): reconcile SQLite doctoring with current stack
seonghobae Aug 16, 2026
c75d518
test(calendar): reject mismatched atomic return rows
seonghobae Aug 16, 2026
3a284bd
chore(calendar): reconcile SQLite adapter with current domain parent
seonghobae Aug 16, 2026
1704808
fix(calendar): validate atomic return identity
seonghobae Aug 16, 2026
e07fd93
chore(calendar): inherit atomic return validation
seonghobae Aug 16, 2026
6f8d30d
test(calendar): isolate atomic return invariants
seonghobae Aug 16, 2026
19f1b31
chore(calendar): inherit isolated return-boundary regression
seonghobae Aug 16, 2026
6f2cbf3
merge(access): reconcile grant domain with current develop
seonghobae Aug 16, 2026
8d56da4
merge(calendar): reconcile subscription domain with current access-gr…
seonghobae Aug 17, 2026
54af635
merge(calendar): reconcile SQLite adapter with current subscription-d…
seonghobae Aug 17, 2026
11374fb
test(calendar): define subscription runtime contract
seonghobae Aug 17, 2026
82baaa0
test(calendar): run runtime API regression in CI
seonghobae Aug 17, 2026
5c7001c
feat(calendar): expose subscription runtime boundary
seonghobae Aug 17, 2026
1e21516
feat(calendar): serve composed runtime app
seonghobae Aug 17, 2026
0c37aae
test(calendar): exercise composed runtime security states
seonghobae Aug 17, 2026
b6d47ba
test(calendar): instrument runtime composition
seonghobae Aug 17, 2026
3b9ab2c
test(calendar): require runtime composition coverage
seonghobae Aug 17, 2026
3756528
fix(calendar): enforce revocation on legacy feed compatibility
seonghobae Aug 17, 2026
6d603de
test(calendar): prove session epoch invalidates subscriptions
seonghobae Aug 17, 2026
295456c
fix(calendar): revoke credentials on membership removal
seonghobae Aug 17, 2026
8e8373b
test(calendar): prove membership removal revokes durable secrets
seonghobae Aug 17, 2026
8b230c8
docs(calendar): record active runtime composition
seonghobae Aug 17, 2026
80cf9c8
docs(calendar): record runtime migration slice
seonghobae Aug 17, 2026
ea14afa
docs(calendar): define runtime security and rollback contract
seonghobae Aug 17, 2026
b9da205
fix(docs): preserve changelog history in calendar child
seonghobae Aug 17, 2026
3f8680b
merge(calendar): reconcile runtime child with current SQLite parent
seonghobae Aug 17, 2026
44eec30
test(calendar): reject impossible feed dates
seonghobae Aug 18, 2026
7c56724
fix(calendar): reject impossible feed dates
seonghobae Aug 18, 2026
fa55b6f
test(calendar): reject unrepresentable exclusive end dates
seonghobae Aug 18, 2026
f259411
fix(calendar): bound exclusive end date rendering
seonghobae Aug 18, 2026
23b865f
docs(calendar): record feed date validity boundary
seonghobae Aug 18, 2026
de98848
test(calendar): reject reversed event ranges
seonghobae Aug 18, 2026
0d1ae19
fix(calendar): omit reversed event ranges
seonghobae Aug 18, 2026
6286c8c
merge(stack): reconcile calendar runtime with current persistence parent
seonghobae Aug 22, 2026
e3bd931
test(calendar): require UTF-8-safe RFC 5545 line folding
seonghobae Aug 22, 2026
a73f974
fix(calendar): fold UTF-8 iCalendar content lines
seonghobae Aug 22, 2026
c515402
docs(calendar): record RFC 5545 folding evidence
seonghobae Aug 22, 2026
1b8bbb0
test(calendar): reject oversized subscription bodies
seonghobae Aug 22, 2026
6127c8f
test(calendar): register body-limit regression
seonghobae Aug 22, 2026
f990b98
fix(calendar): bound subscription management bodies
seonghobae Aug 22, 2026
90304d1
docs(calendar): record bounded management body evidence
seonghobae Aug 22, 2026
0c569b4
chore(stack): reconcile calendar runtime with persistence parent
seonghobae Aug 22, 2026
faf0961
chore(stack): inherit calendar list boundary hardening
seonghobae Aug 22, 2026
e2764e4
test(calendar): require RFC 5545 DTSTAMP
seonghobae Aug 25, 2026
46a836a
fix(calendar): emit required RFC 5545 DTSTAMP
seonghobae Aug 25, 2026
624d3c1
test(calendar): reproduce runtime rate-limit boundary
seonghobae Aug 27, 2026
fa378bf
test(calendar): register runtime rate-limit regression
seonghobae Aug 27, 2026
95485de
test(calendar): preserve PAT auth across limiter repair
seonghobae Aug 27, 2026
4adfdf6
fix(calendar): rate limit runtime routes without auth self-calls
seonghobae Aug 27, 2026
5dcb02d
chore(stack): reconcile calendar runtime with current persistence parent
seonghobae Aug 27, 2026
63f0c6c
chore(stack): inherit calendar SQLite authorization repair
seonghobae Aug 27, 2026
21db752
chore(stack): inherit calendar expiry rotation repair
seonghobae Aug 27, 2026
e6e86c2
chore(stack): inherit bounded calendar usage retention
seonghobae Aug 27, 2026
a9743a9
chore(stack): inherit calendar usage evidence docs
seonghobae Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
- `analytics.js`: EVM, S-curve, CPM, workload, cost, and requirements/RFI/RFP
WBS-estimation readiness analysis.
- `wbs.json`: seed data in the user-specified JSON array format.
- `server/app.mjs`: legacy/core Hono application and its established JSON,
collaboration, billing, export, and compatibility routes.
- `server/runtime_app.mjs`: **active stacked PR work; not yet protected-`develop`
truth**. Production composition wrapper that installs the durable calendar-
subscription schema/revocation hook at bootstrap, adds the bounded calendar
subscription lifecycle/feed routes, and then delegates every other request to
`server/app.mjs`. `server/server.mjs` switches to this wrapper only on the
active child branch.

## CI and security structure

Expand Down Expand Up @@ -54,3 +62,14 @@
secret hash, frozen `calendar_read` purpose, issuance membership epoch,
and normalized lifecycle/audit evidence. Protected route and browser UI
migration remain later issue #413 slices.
- **Active calendar-runtime child; not yet protected-`develop` truth:** the
production composition exposes authenticated create/list/rotate/revoke
management routes and a project-bound `subscription=` ICS feed. Subscription
feed responses are private/no-store/no-referrer, reject mixed credentials,
and cannot authorize JSON APIs, SSE, attachments, or another project. Session
and PAT calendar compatibility remains temporarily available only through the
core database-backed authentication boundary so token-version revocation is
preserved during migration. Membership deletion transactionally revokes the
affected reusable subscriptions and writes revocation evidence. Customer
management UI and final retirement of the legacy `token=` calendar URL remain
later issue #413 slices.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
revocation evidence, a secret-free audit outbox, restart-survival tests, and
c8 registration. Protected route and customer UI migration remain later #413
slices.
- **Active stacked calendar-runtime child; not yet protected-`develop` truth:**
added production composition for calendar subscriptions with authenticated
create/list/rotate/revoke management endpoints, one-time `subscription=` feed
URLs, project/purpose/audience binding, private no-store/no-referrer ICS
responses, mixed-credential rejection, token-version/session-epoch invalidation,
durable membership-removal revocation evidence, and exact API/coverage
regression registration. The staged legacy `token=` calendar path now passes
only through the authoritative database-backed authentication boundary;
customer management UI and final legacy query-token retirement remain later
issue #413 slices.

### Security

Expand Down
101 changes: 101 additions & 0 deletions docs/doctoring/calendar-subscription-runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Calendar subscription runtime composition

Status: **active stacked child; not shipped on protected `develop`**.

Issue: #413. Parent persistence authority: PR #541, which itself depends on the calendar-subscription domain in PR #539.

## Buyer/security outcome

The protected calendar feed still accepts a general ScopeWeave session credential in a URL query parameter. That credential carries substantially more authority than a calendar reader needs and may be exposed by URL-handling systems. The active runtime child composes the separately reviewed calendar credential domain and SQLite persistence into the production server boundary so an operator can create, list, rotate, and revoke a reusable project-calendar credential whose authority is fixed to `calendar_read` for one project and the `scopeweave:calendar` audience.

This slice deliberately remains a staged migration. It adds the durable subscription path but retains the existing `token=` calendar compatibility path temporarily for existing clients. That compatibility path is no longer treated as an independent authentication implementation: it passes through the core `/api/me` authentication boundary, which performs the same database-backed `token_version` revocation checks as normal bearer sessions and PAT handling. The customer management UI and final removal of broad session credentials from calendar URLs remain later #413 work.

## Runtime composition boundary

`server/runtime_app.mjs` is a thin composition wrapper around `server/app.mjs` rather than a copy of the existing application. At bootstrap it:

1. installs the normalized calendar-subscription schema supplied by the parent SQLite adapter;
2. installs an idempotent membership-removal trigger that marks affected reusable subscriptions revoked and writes secret-free revocation evidence before membership deletion commits;
3. wires project management authorization, the live membership/session epoch, cryptographic randomness, the SQLite repository, and the existing audit log into `createCalendarSubscriptionService(...)`; and
4. registers only the calendar-management and calendar-feed routes before delegating every unrelated request to the existing core app.

`server/server.mjs` uses this composition only on the active child branch. Protected `develop` remains unchanged until the prerequisite stack and this child integrate under normal governance.

## Credential and transport contract

The create and rotate responses expose the 256-bit random subscription secret exactly once. Lifecycle listing never returns the plaintext secret, its SHA-256 hash, or the membership epoch. The returned feed path uses `subscription=` rather than `token=` and the reusable credential cannot authorize JSON APIs, SSE, attachments, another project, or another audience.

Calendar-subscription create and rotate JSON bodies are capped at 4 KiB by Hono's `bodyLimit` middleware before JSON parsing. The same ceiling applies to an oversized declared `Content-Length` and to streamed request bytes when no length is declared. Oversized requests return the stable `calendar_subscription_body_too_large` error with HTTP 413 and `Cache-Control: no-store` before the calendar domain service or durable subscription state can be mutated.

A subscription feed request is accepted only when all of these are true:

- the secret has the required format and resolves to the current stored SHA-256 hash;
- project, `calendar_read` purpose, and `scopeweave:calendar` audience match;
- the stored issuance membership epoch equals the live `membership_id:token_version` epoch;
- the credential is neither expired nor revoked;
- the SQLite atomic usage transition independently rechecks the same live epoch; and
- no session query token or `Authorization` credential is mixed into the same subscription request.

Successful subscription-feed responses set `Cache-Control: private, no-store`, `Referrer-Policy: no-referrer`, and `X-Content-Type-Options: nosniff`. The application does not log request bodies or credential values. Calendar values are escaped for RFC 5545 text and all-day `DTEND` remains exclusive. Every emitted RFC 5545 content line is folded to at most 75 UTF-8 octets using `CRLF` plus one SPACE for continuation, and folding iterates Unicode code points so it never splits a UTF-8 multi-octet character. Unfolding therefore reconstructs the complete customer-visible project/task text instead of truncating or corrupting non-ASCII names.

Project task persistence predates the calendar runtime and can contain malformed or impossible date strings. Feed rendering therefore treats persisted task dates as untrusted input: a task is emitted only when both dates are canonical real `YYYY-MM-DD` UTC calendar days and its exclusive next-day `DTEND` is itself representable by RFC 5545's four-digit basic `DATE` form. Invalid months, normalized impossible days, and the `9999-12-31` upper boundary are omitted rather than causing HTTP 500 responses, silently changing the scheduled day, or emitting an extended-year value such as `+01000001`.

## Revocation and recovery

Rotation atomically replaces the current stored hash, so the previous feed URL stops working immediately. Explicit revocation preserves first-transition semantics from the parent domain/adapter.

A `logout-all` or other `token_version` advance changes the live membership/session epoch. Existing reusable calendar credentials from the previous epoch fail authorization immediately; an authorized operator may then rotate the same subscription to bind a new secret to the new epoch. This gives account-level revocation an immediate effect without silently deleting operator-visible subscription state.

Membership removal is stronger. The bootstrap trigger writes a `revoked` event to `calendar_subscription_audit_outbox` and sets `revoked_at_ms` on each affected active subscription within the same SQLite transaction as the membership deletion. Remove-then-rejoin therefore cannot resurrect a reusable secret even if membership identity is later recreated. The core `member.remove` audit record retains the administrative actor, while the calendar outbox retains credential-level revocation evidence without secret material.

## Compatibility and retirement plan

The legacy `token=` calendar path remains an explicit compatibility state, not the target design. During this phase it supports the same current session/PAT authentication semantics as the core API and rejects a request that supplies both query-token and `Authorization` authority. Stale session tokens fail after `token_version` revocation.

The next product slice is the reviewed customer management interaction from the calendar-domain Figma contract. After the UI/client migration and operational acceptance demonstrate that supported calendar clients can create/save/rotate/revoke the dedicated feed URL, the legacy query-session path can be removed with a separate exact-head regression. Rollback must never represent broad session-JWT query transport as the preferred steady-state design.

## TDD and executable acceptance

The runtime API contract was committed before the production composition existed. The first test registered `tests/api/calendar-subscription-runtime.test.mjs` in the canonical API suite while the tested management routes were absent from `server/app.mjs`, establishing the RED boundary before the wrapper implementation.

Two later feed-validity repairs were also established with executed RED evidence before production changes. Test-only `44eec30eb31f43ce9658c97d99af12f4f4d09ac0` persisted `2026-13-01` and `2026-02-30`; Server Tests run `32088800210`, job `95566742208`, reproduced the `RangeError: Invalid time value` feed failure before `isCalendarDay()` was hardened. Test-only `fa55b6f535d6f2c2f5a3420d31f1ae3425b38173` then persisted `9999-12-31`; Server Tests run `32089288786`, job `95568160158`, proved the feed emitted the malformed `DTEND;VALUE=DATE:+01000001` before exclusive-end rendering was bounded. Production commit `f25941198928ad285a2165f7785f27c0fba3bc71` made the second regression GREEN; Server Tests run `32089452553` completed successfully with both `unit-and-api` and `cloud-e2e` passing, while Dependency Review `32089452544` and OSV Scanner `32089452867` also passed on that contributor head. These runs are causal evidence, not final merge authority after later head movement.

The interoperability repair was likewise test-first. Test-only head `e3bd931539f19ea342042a7c11aeaab78fe7af1e` added a long Korean task summary and required every physical iCalendar line to remain within 75 UTF-8 octets while unfolding preserved the complete Unicode value. Server Tests run `32583307921`, `unit-and-api` job `97055782749`, failed at the intended assertion because the renderer emitted an overlong line. Production commit `a73f974efc81085703fe3fe49233fce2162aebca` added UTF-8-safe RFC 5545 content-line folding. Server Tests run `32583381045` then completed successfully: `unit-and-api` job `97055956846` passed the registered API regression and the full unit/API suite, and `cloud-e2e` job `97055956941` passed. Dependency Review `32583381120` and OSV Scanner `32583381290` were also terminal success on that contributor head. The hosted Server Tests checked synthetic merge `cdac7ea7f6f61642d79b959691d74f2fe88317b9` (`Merge a73f974e... into 422f754e...`), so this is causal merge-result evidence rather than exact-contributor-head merge authorization until #523 reaches protected `develop`.

Fresh source inspection then found a separate resource-boundary defect: create and rotate called `c.req.json()` without a request-body byte ceiling. The registered RED head `6127c8f022d079dcaed202edf15179746d17b2ce` added `tests/api/calendar-subscription-body-limit.test.mjs` and required both an oversized declared body and an oversized streamed body to fail before persistence. Server Tests run `32584476314`, `unit-and-api` job `97058694218`, failed at the intended declared-body assertion with HTTP 400 instead of the required 413, proving the application reached JSON/domain handling without a transport bound. That runner checked synthetic merge `568b372d310933999618d0c8d0329fef5540bb77` (`Merge 6127c8f... into 422f754e...`).

Production commit `f990b985e1b6437a7309a65d9d1a6ca898fafc64` added Hono `bodyLimit` at 4 KiB only to the create/rotate management routes. Server Tests run `32584561011` then completed successfully: `unit-and-api` job `97058880349` passed the registered declared/streamed body regressions and full unit/API suite, and `cloud-e2e` job `97058880463` passed. Dependency Review `32584560985` and OSV Scanner `32584561245` were also terminal success. The hosted Server Tests checked synthetic merge `1fb30735a7d1846afdc6b87d05410bcae3f6c9a6` (`Merge f990b985... into 422f754e...`); therefore this is causal merge-result GREEN evidence and not exact-contributor-head merge authority while #523 remains outside protected `develop`.

The current regression covers:

- unauthenticated and cross-tenant management rejection;
- stable invalid-request status mapping;
- create/list and one-time secret disclosure;
- declared and streamed oversized create/rotate body rejection before durable state mutation;
- project/purpose/audience-bound feed authorization;
- private/no-store/no-referrer/nosniff response policy;
- malformed, impossible, and unrepresentable-exclusive-end task-date omission;
- RFC 5545 UTF-8 content-line folding with complete Unicode text after unfolding;
- mixed-credential fail-closed behavior;
- rotation and immediate previous-secret invalidation;
- explicit revocation;
- `logout-all` invalidation followed by authorized epoch re-binding;
- transactional membership-removal revocation plus audit-outbox evidence;
- staged legacy query-token compatibility through current database-backed session authority; and
- coverage-script registration for the production composition module.

Hosted exact-head CI remains authoritative for full statement/branch coverage and broad regression evidence. Repository Server Tests still use GitHub's synthetic pull-request merge ref until the exact-head workflow repair in #523 is protected-integrated, so the bound contributor SHA plus the synthetic checkout identity must both be retained when interpreting current evidence. No predecessor-head result transfers after this branch or any prerequisite head moves.

## Rollback

Before protected integration, rollback is branch-local. After integration, a runtime rollback may disable the new lifecycle endpoints and restore the previous production composition only if incident containment requires it, but it must preserve the normalized subscription and audit data and must not delete revocation/rotation evidence. Re-enabling broad query-session calendar credentials as a permanent security posture is not an acceptable rollback target. Any schema removal requires a separately reviewed data migration/recovery plan.

## References

Desruisseaux, B. (Ed.). (2009). *Internet calendaring and scheduling core object specification (iCalendar)* (RFC 5545). Internet Engineering Task Force. https://doi.org/10.17487/RFC5545

Jones, M., & Hardt, D. (2012). *The OAuth 2.0 authorization framework: Bearer token usage* (RFC 6750). Internet Engineering Task Force. https://doi.org/10.17487/RFC6750

Lodderstedt, T., Bradley, J., Labunets, A., & Fett, D. (2025). *Best current practice for OAuth 2.0 security* (BCP 240; RFC 9700). Internet Engineering Task Force. https://doi.org/10.17487/RFC9700

Sheffer, Y., Hardt, D., & Jones, M. (2020). *JSON Web Token best current practices* (BCP 225; RFC 8725). Internet Engineering Task Force. https://doi.org/10.17487/RFC8725
Loading