Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
38b67fc
⚡ 병렬 외부 네트워크 호출을 위한 Promise.all 적용
seonghobae Aug 4, 2026
5a9dfaa
⚡ 병렬 외부 네트워크 호출을 위한 Promise.all 적용 및 CVE 패치
seonghobae Aug 4, 2026
a3c76d5
fix(review): bound job-status refresh concurrency to chunks of 5
seonghobae Aug 4, 2026
99ff6dd
ci: run one-shot attachment refresh hardening
seonghobae Aug 4, 2026
f5ecb72
ci: remove inactive one-shot repair workflow
seonghobae Aug 4, 2026
63a8f18
ci: validate and apply attachment refresh hardening
seonghobae Aug 4, 2026
bcdb27f
perf(attachments): add bounded status refresh engine
seonghobae Aug 4, 2026
d705f23
test(attachments): cover bounded refresh engine
seonghobae Aug 4, 2026
f8077e0
test(clearfolio): cover status cancellation signal
seonghobae Aug 4, 2026
f455f99
test(api): cover attachment status refresh contract
seonghobae Aug 4, 2026
0d6b439
feat(clearfolio): make status lookups abortable
seonghobae Aug 4, 2026
ff15fca
test(attachments): wire refresh coverage and API regressions
seonghobae Aug 4, 2026
0cc3809
docs(changelog): record bounded attachment refresh
seonghobae Aug 4, 2026
ee4930b
ci: make attachment repair marker-based
seonghobae Aug 4, 2026
62da5d0
Restore scorecard-analysis.yml for branch protection rule
seonghobae Aug 4, 2026
8ebd8cd
docs(attachments): document refresh worker
seonghobae Aug 4, 2026
9f37f79
ci: make attachment repair atomic and marker-based
seonghobae Aug 4, 2026
8fdffb1
ci: patch attachment repair browser setup
seonghobae Aug 4, 2026
a0e53d3
test(e2e): install Chromium for cloud validation
seonghobae Aug 4, 2026
0caf4eb
ci: remove browser bootstrap workflow
seonghobae Aug 4, 2026
0e3cd25
perf(attachments): bound status refresh and remove N+1 queries
github-actions[bot] Aug 4, 2026
4f6565f
chore: remove unrelated scorecard workflow
seonghobae Aug 4, 2026
dddfd60
chore: keep attachment change focused
seonghobae Aug 4, 2026
bb45a51
fix(attachments): enforce request-wide refresh budget
seonghobae Aug 4, 2026
f46c36a
fix(clearfolio): preserve status on HTTP failures
seonghobae Aug 4, 2026
d0a1b44
test(attachments): prove deadline and failure categories
seonghobae Aug 4, 2026
4f1dfe1
test(clearfolio): enforce status endpoint HTTP contract
seonghobae Aug 4, 2026
609c78c
test(attachments): use behavior-only list assertions
seonghobae Aug 4, 2026
73603cd
test(coverage): include Clearfolio status paths
seonghobae Aug 4, 2026
e883548
ci: repair exact-head coverage evidence for PR 419
seonghobae Aug 4, 2026
e34b138
ci: stage PR 419 review repair script
seonghobae Aug 4, 2026
230bafa
ci: arm ready-event repair for PR 419
seonghobae Aug 4, 2026
afeb3c0
fix(ci): make test coverage produce Istanbul evidence
seonghobae Aug 4, 2026
8da3b0e
test(ci): lock coverage-producing script contract
seonghobae Aug 4, 2026
64b7ed5
fix(ci): make coverage evidence deterministic
github-actions[bot] Aug 4, 2026
140bf95
test(ci): document coverage evidence contract
seonghobae Aug 4, 2026
ba5294d
test: reject malformed Clearfolio status responses
seonghobae Aug 4, 2026
a4dd487
fix: preserve attachment status on malformed Clearfolio payloads
seonghobae Aug 4, 2026
13f2402
docs: record malformed status response isolation
seonghobae Aug 4, 2026
6da89d7
test(clearfolio): cover every malformed status response branch
seonghobae Aug 4, 2026
e3b711e
docs(operations): document bounded attachment status refresh
seonghobae Aug 4, 2026
4e84121
docs(operations): add canary rollout and rollback criteria
seonghobae Aug 4, 2026
3d31f17
docs(doctoring): record attachment refresh evidence
seonghobae Aug 4, 2026
5baa055
fix(clearfolio): sanitize downstream errors and validate artifact links
seonghobae Aug 4, 2026
37007e3
test(clearfolio): verify sanitized submit and artifact-link boundaries
seonghobae Aug 4, 2026
e55209d
fix(clearfolio): isolate network errors and prevent HTTPS downgrade
seonghobae Aug 4, 2026
fca35c0
test(clearfolio): cover network isolation and HTTPS downgrade prevention
seonghobae Aug 4, 2026
30d6b71
docs(changelog): record Clearfolio boundary hardening
seonghobae Aug 4, 2026
7845b95
test(clearfolio): reject untrusted status states and status transport…
seonghobae Aug 4, 2026
c782ffb
fix(clearfolio): enforce exact status contract and sanitize status tr…
seonghobae Aug 4, 2026
a3f6d38
docs: record exact Clearfolio status validation
seonghobae Aug 4, 2026
f5c9faf
test(clearfolio): cover mock adapter and HMAC tenant claims
seonghobae Aug 4, 2026
c5d3d95
test(coverage): include Clearfolio mock and HMAC contracts
seonghobae Aug 4, 2026
545de5f
docs(doctoring): record Clearfolio trust-boundary evidence
seonghobae Aug 4, 2026
018c433
fix(attachments): separate skipped refresh rows from deferred work
seonghobae Aug 4, 2026
64c50f2
test(attachments): verify skipped and deferred refresh metrics separa…
seonghobae Aug 4, 2026
c3121af
test(api): distinguish skipped attachments from deferred refresh work
seonghobae Aug 4, 2026
486afb1
test(coverage): require exact Istanbul JSON reporters
seonghobae Aug 4, 2026
783c19e
docs(operations): distinguish refresh deferral from missing identifiers
seonghobae Aug 4, 2026
3f940f9
docs(doctoring): record skipped attachment refresh semantics
seonghobae Aug 4, 2026
fe9ebfa
docs(changelog): record skipped attachment refresh counter
seonghobae Aug 4, 2026
cb56dba
refactor(clearfolio): validate submission records before defaults
seonghobae Aug 4, 2026
b7ddd09
feat(observability): expose sanitized attachment failure categories
seonghobae Aug 4, 2026
ea9397e
test(observability): verify sanitized attachment failure metrics
seonghobae Aug 4, 2026
c48715a
test(api): expose sanitized refresh failure categories
seonghobae Aug 4, 2026
099b813
docs(operations): document low-cardinality refresh failure metrics
seonghobae Aug 4, 2026
f89ff02
docs(doctoring): trace sanitized failure-category evidence
seonghobae Aug 4, 2026
cdbfc51
docs(changelog): include sanitized refresh failure categories
seonghobae Aug 4, 2026
3629e01
ci: repair attachment upload identifier disclosure
seonghobae Aug 4, 2026
8960a9b
fix(attachments): keep conversion identifiers internal
github-actions[bot] Aug 4, 2026
9746592
docs(doctoring): prove upload and list identifier redaction
seonghobae Aug 4, 2026
c0e3111
fix(security): enforce strict database-backed session revocation
seonghobae Aug 4, 2026
3637468
docs(doctoring): record strict session revocation boundary
seonghobae Aug 4, 2026
0d785c0
test(security): prove strict revocation across JWT transports
seonghobae Aug 4, 2026
3a40a8e
test(security): include session revocation API contract
seonghobae Aug 4, 2026
4790878
docs(changelog): record strict cross-transport session revocation
seonghobae Aug 4, 2026
0055199
Merge pull request #443 from ContextualWisdomLab/repair/session-revoc…
seonghobae Aug 13, 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
26 changes: 25 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added regression coverage that prevents array-valued passwords from being
coerced into valid credentials.
- Updated Hono runtime dependencies to patched supported releases.
- Sanitized Clearfolio submission, status, and artifact-link transport failures
so network details and downstream response text cannot reach browser or
diagnostic payloads; rejected unknown or whitespace-padded conversion states
and malformed, unsupported-scheme, or HTTPS-downgrade artifact links.
- Centralized session JWT verification and database-backed `token_version`
revocation across bearer middleware, calendar feeds, server-sent events, and
attachment-view URL transports.
- Made session-token minting fail closed unless the subject, token version, and
lifetime are bounded safe integers, and capped general session lifetime at
seven days so internal callers cannot mint excessive or numerically unsafe
credentials.
- Rejected signed session JWTs with a non-HS256/JWT header, non-object claims,
missing or invalid subject/expiry, or a missing, Boolean, fractional,
negative, unsafe, or otherwise invalid token-version claim before user lookup.
- Added cross-device regression coverage proving that `logout-all` rejects stale
tokens on bearer, calendar, SSE, and attachment-view transports while the
replacement token continues through the same authentication boundary.

### Changed

- Attachment-list status refresh now removes the per-row database lookup,
uses a configurable bounded worker pool with per-item abortable timeouts and
a request-wide latency budget, preserves stale status after downstream,
timeout, malformed-response, and persistence failures, excludes internal
conversion identifiers from responses, reports attempted, changed, failed,
skipped-data, and deferred-budget counters separately, and exposes fixed
low-cardinality timeout, lookup, validation, and persistence failure counters.
- 프로젝트 이름 입력 필드에 입력 예시(placeholder)를 추가하여 사용자 편의성을 개선했습니다.
- 데이터 테이블의 반복되는 액션 버튼에 컨텍스트 정보(작업명)를 포함한 명시적인 ARIA 레이블을 추가하고, 유효성 검사 에러를 폼 필드에 연결하여 접근성을 개선했습니다.
- `createGanttBarElement`, `renderGantt`, `buildWeekdayTimeline`에서 반복적으로 호출되던 `compareDateStrings`를 직접적인 문자열 비교 연산(`>=`, `<=`)으로 교체하여 O(N*D) 복잡도의 캐시 스레싱과 정규식 검사를 방지했습니다.
Expand All @@ -61,4 +85,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [1.0.1] - 2026-06-25
### 성능 개선 (Performance)
- 드래그 앤 드롭 동작 중 `dragover` 이벤트에서 발생하는 O(N) 작업 리스트 검색 성능 병목 문제를, O(1) 해시맵(Map) 기반의 캐싱 조회 로직으로 개선하여 큰 크기의 WBS 리스트에서의 버벅임 현상을 해결했습니다.
- 드래그 앤 드롭 동작 중 `dragover` 이벤트에서 발생하는 O(N) 작업 리스트 검색 성능 병목 문제를, O(1) 해시맵(Map) 기반의 캐싱 조회 로직으로 개선하여 큰 크기의 WBS 리스트에서의 버벅임 현상을 해결했습니다.
76 changes: 76 additions & 0 deletions docs/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,84 @@ persists the database in the `scopeweave-data` volume.
| `ORCHESTRATOR_TOKEN` | with URL | orchestrator Bearer 토큰 (`CONTEXTUAL_ORCHESTRATOR_TOKEN`). |
| `CLEARFOLIO_URL` | for 산출물 viewer | Clearfolio 문서 뷰어 백엔드 주소. Unset → built-in mock (dev/test). |
| `CLEARFOLIO_HMAC_SECRET` | optional | Signs tenant-claim headers (`clearfolio.tenant-claims.hmac-secret`와 동일 값). |
| `SCOPEWEAVE_ATTACHMENT_STATUS_CONCURRENCY` | no (default 8, maximum 32) | Maximum concurrent Clearfolio status lookups during one attachment-list request. Invalid values fall back to 8; values above 32 are clamped. |
| `SCOPEWEAVE_ATTACHMENT_STATUS_TIMEOUT_MS` | no (default 3000, maximum 30000) | Hard caller-side timeout for each Clearfolio status lookup. The AbortSignal is also forwarded downstream. |
| `SCOPEWEAVE_ATTACHMENT_STATUS_BUDGET_MS` | no (default 5000, maximum 60000) | Wall-clock budget for the entire best-effort refresh pass. Work not started before the deadline is deferred to a later list request. |
| `SCOPEWEAVE_RATE_LIMIT_MAX` (+ `SCOPEWEAVE_RATE_LIMIT_WINDOW_MS`) | recommended | Per-IP fixed-window rate limiting (429 + Retry-After). Off when unset. |

## Attachment status refresh operations

The attachment-list API reads `job_id` in its initial project-scoped query and
refreshes only `PENDING` or `RUNNING` rows through a bounded worker pool. It
never performs one database lookup per row. A timeout, unsuccessful HTTP
response, malformed response body, invalid status value, or persistence failure
is isolated to that attachment: ScopeWeave preserves its previously stored
status and still returns the rest of the list. Internal Clearfolio job
identifiers are removed before JSON serialization.

The process metrics endpoint exposes cumulative counters for operational
monitoring:

- `attachmentStatusRefreshAttempted`
- `attachmentStatusRefreshChanged`
- `attachmentStatusRefreshFailed`
- `attachmentStatusRefreshSkipped`
- `attachmentStatusRefreshDeferred`
- `attachmentStatusRefreshTimeoutFailures`
- `attachmentStatusRefreshDownstreamLookupFailures`
- `attachmentStatusRefreshInvalidStatusFailures`
- `attachmentStatusRefreshPersistenceFailures`

`skipped` counts pending rows that cannot be refreshed because their persisted
Clearfolio job identifier is absent or blank. `deferred` counts valid work that
was not started before the request-wide latency budget expired. Keeping these
causes separate prevents malformed stored data from being mistaken for
insufficient concurrency or downstream latency.

The four failure-category counters are fixed, low-cardinality diagnostics whose
sum equals the aggregate `failed` delta for a refresh pass. They contain no job
identifier, URL, downstream response text, or raw exception. The Prometheus
representation uses corresponding `scopeweave_attachment_status_refresh_*`
names. Alert on a sustained increase in `failed`, use the category counters for
triage, investigate `skipped` as a data-quality or migration defect, and compare
`deferred` with list traffic before increasing concurrency or the request-wide
budget. Raise limits conservatively because every worker consumes a downstream
Clearfolio connection; horizontal ScopeWeave replicas multiply the aggregate
concurrency.

### Rollout and alerting

Roll this behavior out behind a canary replica before raising limits across the
fleet. Start with concurrency `2`, the default per-item timeout, and a budget no
longer than the attachment-list latency objective. Compare the canary with the
previous version using the same tenant and Clearfolio environment.

Derive rates from counter deltas over the same observation window:

```text
failure_ratio = failed_delta / max(attempted_delta, 1)
skipped_ratio = skipped_delta / max(attempted_delta + skipped_delta, 1)
deferred_ratio = deferred_delta / max(attempted_delta + deferred_delta, 1)
change_ratio = changed_delta / max(attempted_delta, 1)
```

A high `failure_ratio` indicates downstream, timeout, malformed-response, or
persistence errors and should block rollout. A non-zero `skipped_ratio` indicates
an attachment persistence or migration defect and should be investigated before
changing worker limits. A high `deferred_ratio` indicates that the request-wide
budget is protecting latency at the cost of freshness; first inspect Clearfolio
latency and attachment-list size before increasing worker count or budget. Track
attachment-list p50, p95, and p99 latency beside these ratios. Thresholds must be
derived from observed production baselines and an agreed service-level objective
rather than copied from development data.

Rollback is configuration-first: reduce concurrency and budget without changing
the persisted attachment statuses. If the application version must be rolled
back, the previous implementation can read the unchanged schema; no migration
is required by this feature. Never place Clearfolio job IDs, HMAC material,
request URLs containing credentials, or downstream response bodies in metrics,
logs, traces, or alert annotations.

## Data & scale path

- **Dev / single node**: `node:sqlite` on a persistent volume (this setup). Simple, no external DB.
Expand Down
132 changes: 132 additions & 0 deletions docs/doctoring/attachment-status-refresh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Attachment status refresh and Clearfolio boundary: evidence and design record

## Decision

Attachment listing is a buyer-visible read path and must remain responsive when
Clearfolio is slow, unavailable, or returns malformed data. ScopeWeave therefore
refreshes only stale conversion states through a reusable bounded worker module
that is independent of Hono and SQLite. The Clearfolio HTTP adapter separately
owns downstream transport, tenant headers, response-shape validation, and
artifact-link validation.

The implementation:

1. includes the internal conversion identifier in the initial project-scoped
database query, eliminating one lookup per returned row;
2. limits per-request downstream concurrency through a configurable worker pool;
3. applies a caller-side timeout to every Clearfolio request and forwards the
same `AbortSignal` to `fetch`;
4. applies a wall-clock budget to the complete best-effort refresh pass and
defers valid work that cannot start within that budget;
5. counts pending rows with absent or blank conversion identifiers as skipped
data-quality cases rather than misclassifying them as latency deferrals;
6. validates conversion states against the exact `PENDING`, `RUNNING`,
`SUCCEEDED`, and `FAILED` contract rather than trimming or accepting unknown
strings;
7. preserves the previously stored status after timeout, transport, HTTP,
malformed-response, invalid-state, diagnostic, or persistence failure;
8. persists only changed states;
9. strips internal conversion identifiers from both upload and list JSON before
they cross the browser-facing API boundary;
10. publishes attempted, changed, failed, skipped, and deferred counters without
sensitive downstream payloads or identifiers;
11. publishes fixed timeout, downstream-lookup, invalid-status, and persistence
failure counters so operators can distinguish failure modes without labels or
raw diagnostic data;
12. replaces raw network and downstream response messages with fixed
operation-level submission, status, and artifact-link errors;
13. validates successful submission and artifact-link JSON before property use;
14. accepts artifact links only when they resolve to HTTP(S), and prevents an
HTTPS Clearfolio deployment from returning an HTTP downgrade link; and
15. keeps the in-memory development adapter and HMAC tenant-claim contract under
focused tests so MSA extraction cannot silently change interoperability.

## Standards and threat rationale

OWASP API Security Top 10 2023 identifies unrestricted resource consumption as a
risk when APIs do not bound client interactions or resources. The per-request
worker cap, per-item timeout, request-wide budget, and existing endpoint rate
limit are complementary controls: they bound one list operation, one downstream
operation, the complete refresh pass, and repeated client traffic respectively.

OWASP API10:2023 identifies unsafe consumption of third-party APIs when an
integrating service fails to validate returned data, limit processing resources,
or implement timeouts. ScopeWeave therefore treats Clearfolio responses as
untrusted input even after HTTP success. Rejected JSON, null, primitives,
arrays, missing or non-string fields, empty or whitespace-padded states, unknown
states, malformed links, unsupported URI schemes, and HTTPS downgrade links fail
closed without changing persisted attachment state.

The browser-facing API may serialize adapter errors, so the adapter never copies
DNS names, socket errors, downstream response text, private URLs, or parser
messages into thrown errors. Operation name and HTTP status are the maximum
external diagnostic detail. The refresh engine records only four fixed failure
categories. Detailed downstream diagnostics belong in a separately redacted
operator channel, not a client response, metric label, audit payload, or trace
attribute.

The worker and validation contract is placed in framework- and database-neutral
modules so a future MSA extraction can reuse the same behavior with another HTTP
adapter or persistence implementation. The monolith remains fully operable on
its own. Adapters must pass the same contract suite before they are considered
substitutable.

## Verification contract

Regression tests must prove:

- one hundred pending rows reach but never exceed configured concurrency;
- task-filtered and project-wide lists share one refresh contract;
- unchanged states are not written;
- downstream, timeout, malformed-response, invalid-state, diagnostic, and write
failures are isolated to the affected row;
- pending rows with missing conversion identifiers are counted as skipped;
- valid unstarted work beyond the request budget is counted as deferred;
- skipped and deferred metrics remain distinct in JSON and Prometheus output;
- the four failure-category counters sum to the aggregate failure count and
never contain raw errors, identifiers, URLs, or downstream response text;
- upload responses and attachment-list responses omit the internal Clearfolio
conversion identifier while retaining the public attachment identifier and
current status;
- downstream response text and network details never appear in client JSON;
- the caller `AbortSignal` reaches Clearfolio;
- submission, status, and artifact-link non-success responses expose only fixed
operation-level errors;
- rejected JSON and every malformed successful payload branch fail closed;
- relative and absolute HTTPS links, artifact-token viewer links, and explicitly
configured local HTTP links remain supported;
- HTTPS-to-HTTP downgrade and non-HTTP(S) links are rejected;
- the mock adapter preserves uploaded bytes and status semantics;
- HMAC tenant claims use the documented newline-delimited canonical payload;
- the bounded refresh production module retains 100% statement, branch,
function, and line coverage; and
- every new shipped symbol has complete beginner-readable JSDoc.

## Operational acceptance

Rollout begins with a canary and conservative concurrency. Operators compare
attachment-list p50, p95, and p99 latency with refresh failure, skipped, and
deferral ratios. A high failure ratio blocks rollout and the fixed category
counters identify whether the dominant cause is timeout, downstream lookup,
invalid state, or persistence. A non-zero skipped ratio indicates a persistence
or migration defect and is investigated independently of latency. A high
deferred ratio indicates the latency budget is containing work at the cost of
freshness and requires Clearfolio latency and list-size diagnosis before
increasing resource limits. Rollback is configuration-first and requires no
schema migration.

The rollout review also samples client error payloads, structured logs, traces,
audit exports, and alert annotations to prove that Clearfolio response bodies,
internal DNS names, signed links, HMAC material, and conversion identifiers are
absent. Horizontal replica count is multiplied by configured per-request
concurrency when assessing the downstream connection budget.

## References

OWASP Foundation. (2023a). *API4:2023 unrestricted resource consumption*. OWASP
API Security Top 10.
https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/

OWASP Foundation. (2023b). *API10:2023 unsafe consumption of APIs*. OWASP API
Security Top 10.
https://owasp.org/API-Security/editions/2023/en/0xaa-unsafe-consumption-of-apis/
82 changes: 82 additions & 0 deletions docs/doctoring/session-revocation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Session JWT revocation: evidence and design record

## Decision

Every ScopeWeave transport that accepts a general session JWT uses one
fail-closed verifier. Bearer middleware, calendar feeds, server-sent events, and
attachment-view routes therefore share signature, header, claim, subject, expiry,
and database-backed revocation checks.

The implementation:

1. pins the compact token to an authenticated `HS256` signature and signed `JWT`
type;
2. authenticates the compact representation before interpreting the JOSE header
or claim set;
3. requires a non-array claims object, positive safe-integer subject, future
safe-integer expiry, and non-negative safe-integer token version;
4. requires the subject to exist and compares the signed token version exactly
with the current persisted version;
5. rejects malformed, forged, expired, missing-user, and stale sessions before
tenant or resource lookup;
6. caps general session minting at seven days and rejects fractional, unsafe,
non-positive, or longer lifetimes; and
7. reserves narrower and shorter authority for the opaque access-grant design in
issue #413 rather than overloading the general session JWT.

## Standards rationale

RFC 7519 defines a JWT claims set as a JSON object and defines `sub` and `exp` as
registered claims. ScopeWeave narrows those flexible JSON representations to
safe integers because its database identifiers and token-version comparisons are
integer security boundaries.

RFC 8725 requires callers to perform algorithm verification, validate every
cryptographic operation, use explicit typing for new JWT uses, and apply mutually
exclusive validation rules where different token kinds coexist. ScopeWeave pins
one algorithm and one type for general sessions and does not reuse this JWT
contract for the scoped URL grants planned in issue #413.

RFC 6750 explains that any holder of a bearer token can exercise its authority,
recommends short-lived and audience-scoped credentials, and warns against page
URL transport because browser history and server logs can expose tokens. RFC
9700 updates OAuth security best current practice and prohibits clients from
passing access tokens in URI query parameters. This pull request does not claim
to remove the existing URL transport; it makes revocation and validation
consistent until issue #413 replaces those general credentials with narrowly
scoped opaque grants and separately revocable calendar subscription secrets.

## Verification contract

Regression tests must prove:

- the signer rejects invalid subject, token version, fractional lifetime,
numerically unsafe lifetime, and any general-session lifetime over seven days;
- malformed compact tokens, signatures, JOSE headers, claim-set shapes, subjects,
expiries, and token-version values fail across every transport;
- a correctly signed token for a nonexistent subject fails before resource
lookup;
- two independently minted device sessions work before revocation;
- `logout-all` invalidates both stale sessions on bearer, calendar, SSE, and
attachment-view paths; and
- the replacement session continues through the same authentication boundary.

All changed production helpers require complete JSDoc and 100% statement,
branch, function, and line coverage before the pull request can leave Draft.

## References

Jones, M., Bradley, J., & Sakimura, N. (2015). *JSON Web Token (JWT)* (RFC
7519). Internet Engineering Task Force. https://doi.org/10.17487/RFC7519

Jones, M. B., & 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
Loading