Adds the full bedroom-developer-docs OpenSpec change implementation: - docs/developers/README.md — index page - docs/developers/quick-start.md — bootstrap to working token in 7 steps - docs/developers/concepts.md — AgentIdP, AGNTCY, lifecycle, OAuth 2.0, free tier - docs/developers/guides/README.md — guide index - docs/developers/guides/register-an-agent.md — all fields, validation, common errors - docs/developers/guides/manage-credentials.md — generate, list, rotate, revoke - docs/developers/guides/issue-and-revoke-tokens.md — OAuth 2.0 flow, introspect, revoke - docs/developers/guides/query-audit-logs.md — filters, pagination, 90-day retention - docs/developers/api-reference.md — all 14 endpoints, all error codes, curl examples Also commits deferred OpenSpec housekeeping from previous session: - Archives phase-1-mvp-implementation change to openspec/changes/archive/ - Adds bedroom-developer-docs change artifacts (30/30 tasks complete) - Syncs 4 delta specs to openspec/specs/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.0 KiB
ADDED Requirements
Requirement: Audit events are written internally for all significant actions
The system SHALL automatically create an immutable AuditEvent record for each of the following actions: agent.created, agent.updated, agent.decommissioned, agent.suspended, agent.reactivated, token.issued, token.revoked, token.introspected, credential.generated, credential.rotated, credential.revoked, auth.failed. No API endpoint SHALL allow external creation, modification, or deletion of audit records.
Scenario: Audit event created on agent registration
- WHEN a new agent is successfully registered via
POST /agents - THEN an
AuditEventwithaction: agent.created,outcome: success, andmetadatacontainingagentTypeandowneris persisted
Scenario: Audit event created on failed authentication
- WHEN a
POST /tokenrequest fails due to invalid credentials - THEN an
AuditEventwithaction: auth.failed,outcome: failure, andmetadatacontainingreasonandclientIdis persisted
Scenario: Audit event created on token issuance
- WHEN a token is successfully issued via
POST /token - THEN an
AuditEventwithaction: token.issued,outcome: success, andmetadatacontainingscopeandexpiresAtis persisted
Requirement: Query the audit log with pagination and filtering
The system SHALL return a paginated list of audit events ordered by timestamp descending. The caller SHALL hold a valid Bearer token with audit:read scope. Filtering SHALL support agentId, action, outcome, fromDate, and toDate — all optional, combined with logical AND.
Scenario: Successful audit log query
- WHEN a GET request to
/auditis received with a valid Bearer token withaudit:readscope - THEN the system returns
200 OKwith aPaginatedAuditEventsResponsecontainingdata,total,page, andlimit
Scenario: Filter by agentId
- WHEN a GET request to
/audit?agentId={uuid}is received - THEN only events where
agentIdequals the provided UUID are returned
Scenario: Filter by action
- WHEN a GET request to
/audit?action=token.issuedis received - THEN only events with
action: token.issuedare returned
Scenario: Filter by date range
- WHEN a GET request to
/audit?fromDate=2026-03-01T00:00:00.000Z&toDate=2026-03-28T23:59:59.999Zis received - THEN only events with
timestampwithin the specified range are returned
Scenario: fromDate after toDate rejected
- WHEN a GET request to
/auditis received withfromDatethat is chronologically aftertoDate - THEN the system returns
400 Bad Requestwithcode: VALIDATION_ERRORanddetails.reasonexplaining the invalid date range
Scenario: Insufficient scope rejected
- WHEN a GET request to
/auditis received with a valid Bearer token that does not haveaudit:readscope - THEN the system returns
403 Forbiddenwithcode: INSUFFICIENT_SCOPE
Requirement: Retrieve a single audit event by ID
The system SHALL return a single immutable AuditEvent by its eventId. The caller SHALL hold a valid Bearer token with audit:read scope.
Scenario: Audit event found
- WHEN a GET request to
/audit/{eventId}is received with a valid Bearer token withaudit:readscope and a UUID that exists in the audit log - THEN the system returns
200 OKwith the fullAuditEventobject
Scenario: Audit event not found
- WHEN a GET request to
/audit/{eventId}is received with a UUID that does not exist in the audit log - THEN the system returns
404 Not Foundwithcode: AUDIT_EVENT_NOT_FOUND
Requirement: Free-tier 90-day audit log retention
On the free tier, the system SHALL only return audit events from the last 90 days. Events older than 90 days SHALL be treated as not accessible (return empty results for queries, 404 for direct lookups). The system SHALL return a 400 error with code: RETENTION_WINDOW_EXCEEDED if a fromDate query parameter falls outside the 90-day retention window.
Scenario: Query outside retention window rejected
- WHEN a GET request to
/auditis received withfromDatemore than 90 days before today - THEN the system returns
400 Bad Requestwithcode: RETENTION_WINDOW_EXCEEDEDanddetails.retentionDays: 90
Scenario: Direct lookup of expired event returns 404
- WHEN a GET request to
/audit/{eventId}is received for an event with atimestampolder than 90 days - THEN the system returns
404 Not Foundwithcode: AUDIT_EVENT_NOT_FOUND
Requirement: Rate limiting on audit endpoints
The system SHALL enforce a rate limit of 100 requests per minute per authenticated client on all audit endpoints.
Scenario: Rate limit exceeded on audit endpoint
- WHEN a client sends more than 100 requests to any audit endpoint within a 60-second window
- THEN the system returns
429 Too Many RequestswithX-RateLimit-Limit,X-RateLimit-Remaining: 0, andX-RateLimit-Resetheaders