Skip to content

Commit 155e193

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-9416-resume-value-type-refusal
2 parents eab5c1a + 40fb55e commit 155e193

58 files changed

Lines changed: 5636 additions & 1402 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
"@objectstack/spec": minor
3+
---
4+
5+
feat(spec): `ActionSchema.onSuccess` — post-success navigation for `api`/`script` actions, with `${result.*}` joining the navigate template's interpolation scope (#9566, #9474)
6+
7+
<!-- adr-0087: not-required (accept-set expansion) One new CLOSED optional key
8+
on an existing shape; nothing authorable is renamed, retired or tombstoned, so
9+
there is no conversion to register. Previously-refused spellings stay refused —
10+
three of them now carry guidance pointing at the new key. -->
11+
12+
The maintainer's 2026-08-18 ruling (recorded on #9566, mirrored on #9474)
13+
declares ONE post-success navigation contract for both server-executing action
14+
types instead of two per-type conventions:
15+
16+
- `onSuccess: { navigate, openIn? }` — a strict object, read for
17+
`type: 'api'` and `type: 'script'` only (a refinement refuses it on
18+
`url`/`modal`/`flow`/`form`, where no success event exists for it to ride —
19+
the ADR-0078 posture, same enforcement shape as the `body`-on-non-script
20+
refinement).
21+
- `navigate` is a route/URL template. Its documented interpolation scope is
22+
`${param.*}` + `${ctx.*}` (existing) + **`${result.*}` — NEW: the action's
23+
server response payload** (an `api` action's response body, a `script`
24+
handler's return value), which is what makes "server clones a record → jump
25+
to the new record" declarable: `navigate: '/apps/crm/tasks/${result.id}'`.
26+
The interpolation ENGINE stays the renderer's (objectui `interpolateTarget`);
27+
the spec records the contract.
28+
- `openIn` is the closed enum `'self' | 'newTab'`, defaulting **`'self'`**
29+
(materialized, the file's default convention) — no general navigation DSL.
30+
- The shipped handler-return convention (`{ redirectUrl, openIn? }`,
31+
objectui#2967/#2904) keeps its 17.0.0 semantics: absent `openIn` still means
32+
new-tab (no silent behavior flip for existing handlers); a handler may return
33+
`openIn: 'self'` explicitly.
34+
35+
The console consumer is the downstream objectui half (SPA navigation branch,
36+
`executeAPI` navigation handling, `${result.*}` interpolation), filed
37+
Blocked-by these cards; the liveness ledger records the key at `planned`
38+
strength with the amend-on-landing instruction.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/metadata-protocol": patch
3+
---
4+
5+
Refuse `GET /api/v1/meta/field/<object>.<field>/references` instead of clearing it for deletion
6+
7+
A `field` metadata item is addressed by the composite key `<object>.<field>` (e.g. `account.owner`), but every metadata property that names a field holds the **bare** field name — `view.list.columns[].field`, `dataset.dimensions[].field`, `object.validations[].field`, `object.fields{}` and 150 further non-recursive paths across nine source types. The two sides are drawn from disjoint vocabularies, so the reference scan answered `{ references: [] }` for every field, on every deployment, regardless of real usage.
8+
9+
The admin "Used by" panel renders that empty answer verbatim as *"Nothing in the metadata graph points at this item. Safe to delete."* — an unanswerable question shown as a positive clearance, on the screen where someone decides to delete.
10+
11+
`findReferencesToMeta` now refuses a `field` target with `501 NOT_IMPLEMENTED` in the ADR-0112 envelope, carrying the answerable alternative (`GET /api/v1/meta/object/<object>/references`). Per ADR-0110 D3, a miss and a fault are different facts. Nothing is added to the success response, and no new error code is introduced — this is the same code the route already returns when the protocol cannot compute the graph at all.
12+
13+
Every other target type is unaffected: a genuine "nothing points at this item" still answers `{ references: [] }`.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
Register `FLOW_CONVERSION_CONFLICT` (409) in the ADR-0112 error-code ledger under
6+
`@objectstack/metadata-protocol` (#9567). The code was already live on the wire —
7+
`saveMetaItem`'s flow-conversion rename guard (`protocol.ts`) has thrown it since
8+
ADR-0078 landed, already SCREAMING_SNAKE — but was invisible to
9+
`check:dispatcher-error-vocabulary`'s scan because the site stamps it through a
10+
cast (`(err as any).code = 'FLOW_CONVERSION_CONFLICT'`) rather than the bare-
11+
identifier `assign` shape the scan matched at the time. This is an ordinary,
12+
additive admission: no accept/reject behavior, no producer, and no wire shape
13+
changes.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
"@objectstack/service-analytics": patch
3+
"@objectstack/service-automation": patch
4+
"@objectstack/service-cache": patch
5+
"@objectstack/service-i18n": patch
6+
"@objectstack/service-job": patch
7+
---
8+
9+
docs: five published service READMEs stop documenting an API that does not exist (#9532)
10+
11+
A version bump is the point, not a side effect: these five READMEs are in their
12+
packages' `files` arrays with `private` unset, so they are the pages npm renders —
13+
and a docs-only fix with no bump never reaches npm at all.
14+
15+
Each of the five told a reader to an import of a `Service…` class from its own package
16+
and call a static `.configure({...})` on it. Neither has ever existed: no class in
17+
this repo exposes a static `configure`, and none of `ServiceAnalytics`,
18+
`ServiceAutomation`, `ServiceCache`, `ServiceI18n` or `ServiceJob` is exported by
19+
anything. A reader following any of them wrote code that could not compile. The real
20+
entry point in every case is a kernel plugin constructed with `new`:
21+
`AnalyticsServicePlugin`, `AutomationServicePlugin`, `CacheServicePlugin`,
22+
`I18nServicePlugin`, `JobServicePlugin`.
23+
24+
⛔ A name swap alone would not have been enough, and the gate landed in #9546 is what
25+
proves it: substituting the genuine class while keeping `.configure(...)` turns the
26+
import finding into a call-site finding rather than into silence. Each README is
27+
rewritten against the package's built type surface, and each package's entry is
28+
deleted from `scripts/published-readme-exports.baseline.json` in the same change
29+
(the baseline is reconciled in both directions, so a stale entry fails too).
30+
31+
What was removed as fabricated, beyond the entry point:
32+
33+
- **service-analytics** — a nine-endpoint REST surface (`/analytics/count`, `/sum`,
34+
`/avg`, `/min`, `/max`, `/group-by`, `/time-series`, `/metrics`, `/metrics/:name`)
35+
of which none exists; the real surface is `POST /analytics/query`,
36+
`GET /analytics/meta`, `POST /analytics/sql` and `POST /analytics/dataset/query`.
37+
Also removed: `defineMetric`, `getMetric`, `compare`, `funnel`,
38+
`executeDashboard`, `invalidateCache`, and an `AnalyticsServiceConfig` block whose
39+
four keys (`defaultDriver`, `enableCaching`, `cacheTTL`, `maxMemoryResults`) are
40+
none of the real ones.
41+
- **service-automation**`executeFlow`/`getFlow`/`listFlows`/`getFlowHistory`/
42+
`registerTrigger` as the contract (the real contract is `execute(flowName, context?)`
43+
plus `listFlows()` and a set of optional members), and a five-endpoint REST list that
44+
matches no mounted route. The flow-authoring half of that README was already accurate
45+
and is kept.
46+
- **service-cache**`mget`/`mset`/`del`/`delPattern`/`namespace`/`ttl`/`expire`/
47+
`persist`/`incr`/`incrby`/`decr`/`getOrSet`/`invalidateTag`/`resetStats`, none of
48+
which exist; `ICacheService` has six members. `CacheStats.keys`/`hitRate` corrected to
49+
`keyCount` (there is no `hitRate`), and `set(key, value, { ttl })` corrected to the
50+
real positional `set(key, value, ttl?)` in seconds.
51+
- **service-i18n** — an `await i18n.t('ns:key')` dialect with namespaces, plural
52+
suffixes, `context`, `returnObjects`, `setLocale`/`getLocale`, `formatDate`/
53+
`formatNumber`/`formatRelative`, `addLocale`/`removeLocale`/`reload`, `getCoverage`/
54+
`getMissingKeys`, and a `{{lng}}/{{ns}}` file layout. The real `t()` is synchronous
55+
and takes the locale positionally — `t(key, locale, params?)` — over one
56+
`{locale}.json` file per locale. The `POST /i18n/translate` endpoint does not exist.
57+
- **service-job**`scheduleInterval`/`scheduleOnce`/`getJob`/`stopJob`/`resumeJob`/
58+
`deleteJob`/`runNow`/`getJobHistory`/`clearHistory`/`getLastExecution`, and a
59+
`schedule({ name, schedule, handler })` options-object call. The real `schedule` is
60+
positional — `schedule(name, schedule, handler, options?)` — and returns `void`.
61+
Retry defaults corrected to the enforced ones (`maxRetries: 0`,
62+
`backoffMultiplier: 1`).
63+
64+
Two capability claims are corrected rather than deleted, because the source is what
65+
decides:
66+
67+
- **service-cache** advertised Redis as production support. `RedisCacheAdapter` throws
68+
`RedisCacheAdapter not yet implemented` from every method, and
69+
`new CacheServicePlugin({ adapter: 'redis' })` throws during `init` rather than
70+
falling back to memory. The README now says so at the top and points at registering
71+
a custom `ICacheService` under the slot instead.
72+
- **service-job**'s `adapter: 'interval'` stores cron registrations that never fire.
73+
That is now stated in the adapter table rather than left for a reader to discover.
74+
75+
No compliance claim (SOC 2 / HIPAA / GDPR or similar) was found in any of the five —
76+
the shape that raised `plugin-audit`'s severity in #9517 is absent here.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
Published agent-authoring prompts now reference real exports.
6+
7+
`prompts/create-new-project.md`, `prompts/implement-objectql.md` and
8+
`prompts/implement-objectos.md` told agents to import five symbols that
9+
`@objectstack/spec` does not export. Four failed loudly. The fifth did not:
10+
`import { Object } from '@objectstack/spec/data'` does not resolve, so the
11+
annotation in `export const AccountObject: Object = { ... }` bound to the
12+
**JavaScript global** `Object` instead — metadata authored from that prompt
13+
type-checked against a type that constrains nothing.
14+
15+
- Object definitions now use the house authoring convention measured in the
16+
example apps, `ObjectSchema.create({ ... })`, which genuinely validates.
17+
Correcting it exposed that the prompt's own example set `enable.audit` /
18+
`enable.workflow`, neither of which exists; they are now `trackHistory` /
19+
`files`, the pair the schema's own docstring uses.
20+
- `implement-objectql.md` keeps the real `Field` and `QuerySchema` imports and
21+
derives the object metadata type as `z.infer<typeof ObjectSchema>`, matching
22+
both `prompts/instructions.md` ("interfaces must be inferred from Zod") and
23+
spec's own `src/contracts/schema-driver.ts`.
24+
- `ManifestSchema` becomes `ObjectStackDefinitionSchema` from the package root:
25+
the prompt's subject is `objectstack.config.ts`, which is neither of the
26+
`/system` manifests.
27+
- `IdentitySchema` / `PolicySchema` have no bare referent; Rule #2 now names
28+
`RLSUserContextSchema` and `RowLevelSecurityPolicySchema` from
29+
`@objectstack/spec/security`.
30+
- The three non-existent "Key Files to Watch" paths
31+
(`system/{manifest,identity,events}.zod.ts`) now point at `stack.zod.ts`,
32+
`security/rls.zod.ts` and `kernel/events.zod.ts`.

0 commit comments

Comments
 (0)