@agentsfleet/orly 0.14.5 → 0.14.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/CHANGELOG.md +13 -0
- package/docs/REST_API_DESIGN_GUIDELINES.md +17 -8
- package/docs/RULE_ENFORCEMENT.md +3 -3
- package/docs/SCHEMA_CONVENTIONS.md +10 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ TypeSafe's Jev model supplies runtime advice through explicit `orly judge` reque
|
|
|
78
78
|
|
|
79
79
|
See [releases](https://github.com/agentsfleet/orly/releases) for published versions.
|
|
80
80
|
The install commands below fetch the published package.
|
|
81
|
-
The release workflow publishes 0.14.
|
|
81
|
+
The release workflow publishes 0.14.7 after its version change merges to `main`.
|
|
82
82
|
|
|
83
83
|
---
|
|
84
84
|
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.14.7 — 2026-10-17
|
|
4
|
+
|
|
5
|
+
API instants become RFC 3339 strings, and agentsfleet's schema stores them as `TIMESTAMPTZ(3)` under a clock rule that reads the time after a lock wait.
|
|
6
|
+
|
|
7
|
+
- **REST guide** — `_at` fields are RFC 3339 strings in UTC, OpenAPI `format: date-time`; epoch integers no longer represent instants, and filters state their boundaries.
|
|
8
|
+
- **Schema conventions** — timestamps are `TIMESTAMPTZ(3)`; lifecycle stamps come from `now()`, locking validity checks lock first and then read `clock_timestamp()`, and sweeps compare against `statement_timestamp()`.
|
|
9
|
+
|
|
10
|
+
## 0.14.6 — 2026-10-17
|
|
11
|
+
|
|
12
|
+
agentsfleet's schema conventions no longer require migrate to refuse an older migrator's ledger.
|
|
13
|
+
|
|
14
|
+
- **Schema conventions** — agentsfleet's databases start empty under SQLx's `Migrator`, so no earlier ledger exists to refuse.
|
|
15
|
+
|
|
3
16
|
## 0.14.5 — 2026-10-17
|
|
4
17
|
|
|
5
18
|
agentsfleet's schema conventions carry the owner-signed Postgres rules, and specs may run to 500 lines.
|
|
@@ -35,7 +35,7 @@ exception; an unchecked item cannot silently become a pass.
|
|
|
35
35
|
- [ ] **List envelope** is exactly `{items, total: int|null, next_cursor: string|null}` — no synonyms (§3)
|
|
36
36
|
- [ ] **Bulk endpoints** use `207` with the canonical per-item shape (§3)
|
|
37
37
|
- [ ] **Null vs omit** — absent optionals omitted, `null` reserved for "explicitly cleared" (§3)
|
|
38
|
-
- [ ] **Datetime fields** are
|
|
38
|
+
- [ ] **Datetime fields** are RFC 3339 strings in UTC (`Z`) with `_at` suffix; no epoch integers (§4)
|
|
39
39
|
- [ ] **Duration fields** are integers with `_ms` or `_seconds` suffix; no bare `timeout`/`ttl`/`duration` (§4)
|
|
40
40
|
- [ ] **Status codes** — 409 includes `current_state`; 412 includes `etag`; 429 includes `Retry-After` + `X-RateLimit-*` (§4)
|
|
41
41
|
- [ ] **ETag/`If-Match`** wired for any resource with realistic concurrent edits (§4)
|
|
@@ -120,7 +120,7 @@ If the parent ID is in the path, never repeat it in the body.
|
|
|
120
120
|
|
|
121
121
|
- **Plural for collections, singular for items**
|
|
122
122
|
- **`_id` suffix** for identifiers (`product_id`, `agent_id`) — never bare `id` except as the resource's own primary key field
|
|
123
|
-
- **`_at` suffix** for datetimes; values are
|
|
123
|
+
- **`_at` suffix** for datetimes; values are RFC 3339 strings in UTC (§4)
|
|
124
124
|
- **Unit suffix** for durations: `_ms` or `_seconds` (§4) — never bare `timeout`/`ttl`/`interval`/`duration`/`expiration`
|
|
125
125
|
- **Adjectives before nouns** (`completed_items`, not `items_completed`)
|
|
126
126
|
- **No `is_` prefix** on booleans (`enabled`, not `is_enabled`)
|
|
@@ -173,7 +173,7 @@ Endpoints that can't complete inside the request window MUST follow this convent
|
|
|
173
173
|
1. The kicking POST returns `202 Accepted` with `Location: /v1/operations/{operation_id}` and a body containing `operation_id` and `status: "pending"`.
|
|
174
174
|
2. `GET /v1/operations/{operation_id}` returns:
|
|
175
175
|
```json
|
|
176
|
-
{ "operation_id": "...", "done": false, "status": "running", "started_at":
|
|
176
|
+
{ "operation_id": "...", "done": false, "status": "running", "started_at": "2026-10-17T18:06:49.123Z" }
|
|
177
177
|
```
|
|
178
178
|
When `done: true`, the body carries either `result` (the final resource, inline) or `error` (an RFC 7807 envelope per §5).
|
|
179
179
|
3. Terminal states are `succeeded`, `failed`, `cancelled`. No others.
|
|
@@ -213,7 +213,7 @@ The resource itself, no envelope:
|
|
|
213
213
|
{
|
|
214
214
|
"id": "01HZQ...",
|
|
215
215
|
"name": "platform-ops",
|
|
216
|
-
"created_at":
|
|
216
|
+
"created_at": "2026-10-17T18:06:49.123Z"
|
|
217
217
|
}
|
|
218
218
|
```
|
|
219
219
|
|
|
@@ -227,7 +227,7 @@ GET /products?status=active&sort=-created_at&starting_after=01HZQ...&limit=50
|
|
|
227
227
|
|
|
228
228
|
- **Filtering grammar — exactly one form per case:**
|
|
229
229
|
- **Equality:** `?status=active` (single value), `?status=active,paused` (multi-value, comma-separated, single key).
|
|
230
|
-
- **Time ranges:** `?created_after=<
|
|
230
|
+
- **Time ranges:** `?created_after=<RFC 3339>&created_before=<RFC 3339>`, both exclusive; an endpoint that differs states its boundaries in the parameter description. Bracket grammar (`?created_at[gte]=...`) is forbidden.
|
|
231
231
|
- **No boolean explosions.** Don't add `?include_x=true&include_y=true` — use `?include=x,y` with a documented enum of legal values, OR don't expose a knob.
|
|
232
232
|
- **Sorting:** `sort=field` ascending; `sort=-field` descending. Single sort key per request — no multi-key.
|
|
233
233
|
- **Pagination — keyset.** Request: `?starting_after=<resource_id>&limit=<int>`;
|
|
@@ -318,13 +318,22 @@ If you find yourself wanting another status code, check RFC 7231/7807 — don't
|
|
|
318
318
|
|
|
319
319
|
### Datetime fields
|
|
320
320
|
|
|
321
|
-
**
|
|
321
|
+
**RFC 3339 strings, serialized as JSON strings, OpenAPI `type: string, format: date-time`.** Field name uses the `_at` suffix.
|
|
322
322
|
|
|
323
323
|
```json
|
|
324
|
-
"created_at":
|
|
324
|
+
"created_at": "2026-10-17T18:06:49.123Z"
|
|
325
325
|
```
|
|
326
326
|
|
|
327
|
-
|
|
327
|
+
1. Responses MUST emit UTC with the `Z` designator.
|
|
328
|
+
2. Requests MAY carry any valid numeric UTC offset. The server MUST normalize an accepted instant to UTC.
|
|
329
|
+
3. Epoch integers MUST NOT represent an instant.
|
|
330
|
+
4. An invalid or out-of-range instant MUST return `400` with a field-specific `detail` (§5).
|
|
331
|
+
5. Timestamp filters MUST document whether each boundary is inclusive or exclusive. An opaque pagination cursor MUST carry the complete ordering key at the database's precision.
|
|
332
|
+
6. Shared validation MUST enforce the documented input range and precision.
|
|
333
|
+
|
|
334
|
+
<!-- oracle-packs:start product.agentsfleet -->
|
|
335
|
+
For `agentsfleet`, wire types hold `jiff::Timestamp` and use its standard serialization; no handler converts an instant by hand. Postgres stores instants as `TIMESTAMPTZ(3)`, so the API, the cursor and the database agree on millisecond precision.
|
|
336
|
+
<!-- oracle-packs:end -->
|
|
328
337
|
|
|
329
338
|
When the field has not yet been set (e.g. an unrevoked key's `revoked_at`), serialize as JSON `null` and declare `nullable: true` in the schema.
|
|
330
339
|
|
package/docs/RULE_ENFORCEMENT.md
CHANGED
|
@@ -7,14 +7,14 @@ regenerates this file and fails on any difference. To update it, run
|
|
|
7
7
|
| Rule document | enforced by | judged | acknowledged | classified | trigger |
|
|
8
8
|
|---|---|--:|--:|--:|---|
|
|
9
9
|
| `docs/LOGGING_STANDARD.md` | `LOG` → `logging.sh` | 10 | 13 | 30/30 | mechanical |
|
|
10
|
-
| `docs/REST_API_DESIGN_GUIDELINES.md` | — | 0 | 0 | 0/
|
|
11
|
-
| `docs/SCHEMA_CONVENTIONS.md` | — | 0 | 0 | 0/
|
|
10
|
+
| `docs/REST_API_DESIGN_GUIDELINES.md` | — | 0 | 0 | 0/75 | mechanical |
|
|
11
|
+
| `docs/SCHEMA_CONVENTIONS.md` | — | 0 | 0 | 0/13 | mechanical |
|
|
12
12
|
| `docs/DOCUMENTATION_RULES.md` | — | 0 | 0 | 0/22 | latent |
|
|
13
13
|
| `docs/LIFECYCLE_PATTERNS.md` | — | 0 | 0 | 0/22 | mechanical |
|
|
14
14
|
| `docs/CHANGELOG_VOICE.md` | — | 0 | 0 | 0/3 | latent |
|
|
15
15
|
| `docs/VERIFY_TIERS.md` | — | 0 | 0 | 0/4 | uncited |
|
|
16
16
|
| `docs/greptile-learnings/RULES.md` | — | 0 | 0 | 0/115 | mechanical |
|
|
17
|
-
| **corpus** | | | | **30/
|
|
17
|
+
| **corpus** | | | | **30/284** | |
|
|
18
18
|
|
|
19
19
|
## How to read this
|
|
20
20
|
|
|
@@ -21,7 +21,7 @@ Canonical reference for `agentsfleet` database schema patterns. All new tables *
|
|
|
21
21
|
|
|
22
22
|
## Migrator
|
|
23
23
|
|
|
24
|
-
SQLx's `Migrator` applies the slots from the explicit list in `rustd/crates/afd_db/src/migration.rs` (`Migrator::with_migrations`; the `migrate` feature only, `macros` stays off). It keeps checksums, so an edited applied slot is refused, and records the ledger in the `audit` schema. Locking is ours: SQLx's lock is off (`set_locking(false)`) and a bounded `pg_try_advisory_lock` poll wraps the run, so a held lock fails loudly instead of hanging a deploy.
|
|
24
|
+
SQLx's `Migrator` applies the slots from the explicit list in `rustd/crates/afd_db/src/migration.rs` (`Migrator::with_migrations`; the `migrate` feature only, `macros` stays off). It keeps checksums, so an edited applied slot is refused, and records the ledger in the `audit` schema. Locking is ours: SQLx's lock is off (`set_locking(false)`) and a bounded `pg_try_advisory_lock` poll wraps the run, so a held lock fails loudly instead of hanging a deploy.
|
|
25
25
|
|
|
26
26
|
## Schema File Organization
|
|
27
27
|
|
|
@@ -93,16 +93,21 @@ Every root a user or operator can delete — draft, user, Library card, fleet, w
|
|
|
93
93
|
|
|
94
94
|
## Timestamps
|
|
95
95
|
|
|
96
|
-
- **Type:** `
|
|
97
|
-
- **
|
|
96
|
+
- **Type:** `TIMESTAMPTZ(3) NOT NULL` (nullable for a NULL marker), so the database, the Rust `jiff::Timestamp` and the API agree on millisecond precision. Never `BIGINT` epoch integers or `TIMESTAMP` without a time zone.
|
|
97
|
+
- **Server lifecycle stamps** (`created_at`, `updated_at`) are written by the statement as `now()`: one database clock, one instant per transaction. No column `DEFAULT`; every write names its stamp in its `.sql` file.
|
|
98
|
+
- **Deadlines** are computed in SQL as `clock_timestamp() + $ttl::interval`, with the TTL bound as an exact interval.
|
|
99
|
+
- **A locking validity check** ("is this lease still live?") locks the target rows first, then reads `clock_timestamp()` once in a `MATERIALIZED` step that depends on the locked rows. A clock read in the `WHERE` or select list of a locking statement can run before the lock wait and accept an expired row.
|
|
100
|
+
- **A non-locking read or `SKIP LOCKED` sweep** compares against `statement_timestamp()`, which an index can use; `clock_timestamp()` cannot be an index bound.
|
|
101
|
+
- **`now()` and `CURRENT_TIMESTAMP` never decide an expiry**, because both are fixed at transaction start.
|
|
102
|
+
- A time supplied by another system is stored as given in its own column, apart from the received or processed stamp.
|
|
98
103
|
|
|
99
104
|
## Standard Columns
|
|
100
105
|
|
|
101
106
|
| Column | Type | Required | Notes |
|
|
102
107
|
|--------|------|----------|-------|
|
|
103
108
|
| `id` | `UUID PRIMARY KEY` | Yes | UUIDv7, application-minted |
|
|
104
|
-
| `created_at` | `
|
|
105
|
-
| `updated_at` | `
|
|
109
|
+
| `created_at` | `TIMESTAMPTZ(3) NOT NULL` | Yes | `now()` at INSERT |
|
|
110
|
+
| `updated_at` | `TIMESTAMPTZ(3) NOT NULL` | If the row ever changes | `now()` at INSERT and every UPDATE |
|
|
106
111
|
|
|
107
112
|
## Audit Pattern
|
|
108
113
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentsfleet/orly",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.7",
|
|
4
4
|
"description": "Repository-scoped engineering harness: renders agent rules, materialises the gates that enforce them, and proves the PR boundary \u2014 for any coding agent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|