Skip to content

Commit 8ad3de3

Browse files
MajorTalclaude
andcommitted
chore: archive project-lifecycle-surface-sync + sync main spec
Move the completed change to openspec/changes/archive/ and promote the delta spec to openspec/specs/project-lifecycle-surface/spec.md so the canonical spec set reflects the shipped behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cfd17d1 commit 8ad3de3

6 files changed

Lines changed: 57 additions & 1 deletion

File tree

openspec/changes/project-lifecycle-surface-sync/.openspec.yaml renamed to openspec/changes/archive/2026-04-14-project-lifecycle-surface-sync/.openspec.yaml

File renamed without changes.

openspec/changes/project-lifecycle-surface-sync/design.md renamed to openspec/changes/archive/2026-04-14-project-lifecycle-surface-sync/design.md

File renamed without changes.

openspec/changes/project-lifecycle-surface-sync/proposal.md renamed to openspec/changes/archive/2026-04-14-project-lifecycle-surface-sync/proposal.md

File renamed without changes.

openspec/changes/project-lifecycle-surface-sync/specs/project-lifecycle-surface/spec.md renamed to openspec/changes/archive/2026-04-14-project-lifecycle-surface-sync/specs/project-lifecycle-surface/spec.md

File renamed without changes.

openspec/changes/project-lifecycle-surface-sync/tasks.md renamed to openspec/changes/archive/2026-04-14-project-lifecycle-surface-sync/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@
3434

3535
## 6. Memory + sync bookkeeping
3636

37-
- [ ] 6.1 After the change ships, update `~/.claude/projects/-Users-talweiss-Developer-run402-public/memory/project_last_integration.md` with the new last-synced commit (`2ab48095` from run402) and the run402-public commit that ships this change
37+
- [x] 6.1 After the change ships, update `~/.claude/projects/-Users-talweiss-Developer-run402-public/memory/project_last_integration.md` with the new last-synced commit (`2ab48095` from run402) and the run402-public commit that ships this change
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## ADDED Requirements
2+
3+
### Requirement: Lifecycle-state signals surfaced on 402
4+
5+
When the gateway returns 402 with lifecycle fields on a control-plane mutating route (deploy, secret rotation, subdomain claim, function upload, publish, contract ops, domain ops, email-domain ops, mailbox ops), the CLI/MCP tool output SHALL extract and display the lifecycle state, the time the project entered it, and the time of the next transition, alongside the existing `renew_url` / `usage` / `hint` fields.
6+
7+
#### Scenario: Past-due 402 on a deploy
8+
9+
- **WHEN** a deploy tool receives `HTTP 402` with body `{ "message": "Project is past_due", "lifecycle_state": "past_due", "entered_state_at": "2026-04-01T00:00:00Z", "next_transition_at": "2026-04-15T00:00:00Z", "renew_url": "https://..." }`
10+
- **THEN** the tool result text includes the HTTP status, the message, a line showing `lifecycle_state: past_due`, the entered-at and next-transition-at timestamps, and a next-step hint directing the agent to renew the tier
11+
12+
#### Scenario: 402 without lifecycle fields
13+
14+
- **WHEN** a tool receives `HTTP 402` with body that only contains `message` and `usage` (no `lifecycle_state`)
15+
- **THEN** output renders the existing usage/renew_url guidance unchanged; no "lifecycle_state" line is emitted
16+
17+
### Requirement: Subdomain reservation 409 produces distinct guidance
18+
19+
When `POST /subdomains/v1` (or equivalent subdomain-claim route) returns `HTTP 409`, tool output SHALL include actionable guidance that the name is currently reserved (e.g., under another wallet's grace window) and suggests waiting for the reservation to lapse or choosing another name, distinct from the 403 not-authorized path.
20+
21+
#### Scenario: Subdomain reserved during grace window
22+
23+
- **WHEN** a subdomain-claim tool receives `HTTP 409` with body `{ "message": "Subdomain reserved", "hint": "Name held for original owner during grace period" }`
24+
- **THEN** the tool result includes the 409 status, the message and hint, and next-step text mentioning the reservation rather than reusing the 403 lease-expired guidance
25+
26+
### Requirement: archive_project tool text reflects grace-period vocabulary
27+
28+
The `archive_project` MCP tool description and success message, and the corresponding CLI subcommand output, SHALL use the new lifecycle vocabulary (purge / grace window) rather than the obsolete "archived" wording. The tool name, CLI subcommand name, HTTP method, and endpoint path SHALL remain unchanged.
29+
30+
#### Scenario: Successful archive
31+
32+
- **WHEN** the agent invokes `archive_project` on a live project and the API returns 200
33+
- **THEN** the tool returns success text that uses "purged" (or equivalent purge/grace vocabulary) and does not describe the project as "archived"
34+
35+
#### Scenario: Tool description advertised via MCP list
36+
37+
- **WHEN** an MCP client lists available tools
38+
- **THEN** the description for `archive_project` reflects the soft-delete lifecycle (grace window → purge) and does not claim the project becomes "archived" after 7 days
39+
40+
### Requirement: SKILL.md runtime sections document the grace state machine
41+
42+
Both `SKILL.md` (MCP) and `openclaw/SKILL.md` SHALL describe the project lifecycle as the four-stage `active → past_due → frozen → dormant → purged` state machine (~104-day grace), note that the end-user data plane continues to serve throughout, and state that owner control-plane mutating endpoints return 402 once the project is past_due. The prior "7-day read-only grace, then archived" wording SHALL be removed.
43+
44+
#### Scenario: Skill lifecycle paragraph
45+
46+
- **WHEN** a reader loads `SKILL.md` or `openclaw/SKILL.md`
47+
- **THEN** the lifecycle section describes the four stages, the ~104-day total window, the data-plane vs control-plane distinction, and that renewing during grace reactivates the project
48+
49+
### Requirement: Lifecycle-state extraction is defensive
50+
51+
`formatApiError` SHALL read `lifecycle_state`, `entered_state_at`, `next_transition_at`, and `scheduled_purge_at` from the response body only when present; missing or null fields MUST NOT produce a line in the output nor throw.
52+
53+
#### Scenario: Partial lifecycle body
54+
55+
- **WHEN** a 402 body contains `lifecycle_state` and `entered_state_at` but omits `next_transition_at`
56+
- **THEN** output lists the present fields and omits the missing one, with no placeholder text such as `undefined` or `null`

0 commit comments

Comments
 (0)