Skip to content

Releases: NousVigil/archstone

v0.34.0

Choose a tag to compare

@github-actions github-actions released this 11 Oct 18:16
Immutable release. Only release title and notes can be modified.
a22890b

Added

  • boolean semantic type (Experimental). A field can now be declared type: boolean or list: boolean, on inputs and outputs and inside resources. It means a JSON true or false and nothing else, and lowers to {"type": "boolean"} in inputSchema and outputSchema. Nothing is coerced on either side: an input of "true", 1 or null (for a required field) is refused as input_invalid naming the field before the provider is called, and a provider value that is not a JSON boolean (0/1, "true", "t") is the wrong shape for its field, which is a contract violation when the field is required and an omitted, degraded field when it is optional. false counts as present. A Postgres boolean column reaches a boolean field as a JSON boolean, and @archstone/agent carries the type through unchanged. boolean is the first plain scalar whose output value the response mapper type-checks (quantity and text still accept any primitive; see #157). Packages: @archstone/compiler, @archstone/schema, @archstone/emitter-support.

Changed

  • archstone init and archstone adopt now emit boolean. An OpenAPI type: boolean and a Postgres boolean column (previously skipped with column-type-not-expressible) map to boolean, and adopt offers an observed JSON true/false (and an array of them as list: boolean) instead of refusing it with no-boolean-type. A union such as [boolean, string] still resolves to string. For an author who had declared a flag as string and moves it to boolean, archstone diff reports the change as breaking (input-retyped / output-retyped), because the contract really does change. Packages: @archstone/init, @archstone/runtime.

Fixed

  • The README's Claude Code key instructions led to a failing command. It named the --header "Authorization: Bearer <key>" flag without saying where it goes, and placed before the server name it fails with error: missing required argument 'name', because --header takes every argument that follows it. The README now gives the whole command, with the header after the name and URL, as the showcase README already does.

  • Showcase prompts that only worked as a follow-up. Pasted alone into a fresh conversation against the hosted demo, the suggested prompts of S-02, S-06 to S-09, S-11 and S-12 ("Book that quote…", "Pay for the booking…", "Tell me more about Casa Alfama") made a model ask for the missing context instead of calling a tool. Each now names the stay, the dates, the guests and any booking number it needs, so it works on its own (checked with a model, one prompt per conversation). Keyed rows (S-06 to S-09) gain an optional ownAi note in scenarios.json saying what an AI app connected without a key will see, and the showcase README shows how to send a demo key from a client that lets you set an Authorization header (Claude Code does).

  • An IR that names a semantic type the runtime does not know is now refused at load, not lowered as string. @archstone/emitter-support's Registry constructor, which @archstone/runtime (archstone serve) and @archstone/agent (fromIR) both build, now throws UnknownSemanticTypeError naming the type and the field path (for example tools[shop.get].input.flag), for input, output, list-element and resource fields alike. The JSON Schema lowering, the input validator and the response mapper throw the same error rather than defaulting to a string, so a runtime older than the compiler no longer advertises a newer type as string and rejects valid values with "expected string". This protects runtimes from 0.34.0 onward: a runtime older than 0.34.0 still falls back to string for an unknown type, so keep the compiler, the runtime and @archstone/agent on the same version. UnknownSemanticTypeError is exported from @archstone/emitter-support, @archstone/runtime and @archstone/agent.

v0.33.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 23:20
Immutable release. Only release title and notes can be modified.
d705f42

Upgrading: inputs are now enforced, and permissive manifests may see new refusals. From this
release a capability's declared input: is checked before the provider is called, and the
advertised inputSchema is closed (additionalProperties: false). A call whose arguments do not
match the declared contract, including one that carries an undeclared key, is refused with
isError: true and _meta["dev.archstone/input_invalid"]
({ error: "input_invalid", capability, problems: [{ path, expected }], truncated? }); the
embedded execute() returns denial.reason: "input_invalid". If your agents or manifests relied
on permissive inputs (extra keys, numbers where strings are declared, free-text dates, negative
party counts), either fix the caller to send what the capability declares, or widen the
capability's input: so it declares what you actually accept, then re-run archstone apply.
The details are the first entry under Changed below.

Changed

  • BEHAVIOUR CHANGE: a capability's declared input: is now enforced before the provider is called. Until now inputSchema was advertised but never checked, so arguments of the wrong shape (an object where a location string is declared, a free-text date, a negative party count, an undeclared key) were forwarded to the backend, and only the backend's own validation stopped them. callTool (MCP, stdio and HTTP) and execute() (embedded) now validate the arguments with one shared validateInput in @archstone/emitter-support, after the lifecycle and policy gates and before rate limiting and any connector work. A mismatch returns isError: true with _meta["dev.archstone/input_invalid"] ({ error, capability, problems: [{ path, expected }], truncated? }, at most 16 problems), or ExecuteResult.denial = { reason: "input_invalid", capability, problems }, and the audit record is phase: "denied", denialReason: "input_invalid". The refusal names declared field paths and fixed expectations only; it never contains a value or an undeclared key name the caller sent. Nothing is coerced: a wrong type, a missing required field, a value outside an enum, a malformed date/date-range/date-time, a non-integer or negative party count, a malformed money, and any undeclared key (top level, or inside money, party, date-range) are all refused; null on an optional field still counts as absent. The advertised inputSchema is now closed to match (additionalProperties: false at every object level, minimum: 0 on party counts), so a client that sent extra keys, numbers for strings or free-text dates and was accepted before will now be refused. execution.schema.json's denialReason enum gains input_invalid.

Fixed

  • A required field that arrived in the wrong shape was reported as missing (#196). A backend that sent a string for a quantity/money field produced contract violation … missing required field(s): pricePerNight, which sent the reader looking for a field that was there. The violation now keeps the two apart, in the text and in _meta["dev.archstone/contract_violation"]: missing lists only fields the provider did not send, and a new invalid lists fields it sent in the wrong shape as { field, expected }, where expected is the declared type. invalid is present only when non-empty, so a violation with nothing malformed is byte-identical to before; missing keeps its key and shape, but a malformed field is no longer in it. An optional field in the wrong shape is likewise named in a separate degraded note and in invalid (it also stays in degraded, which still lists every optional field left out of the result). ExecuteResult and ContractRecording carry the same invalid. The provider's value is never echoed.

  • The Showcase's searches invented stays and ignored budget and preferences. wanderlust_search returned made-up "Generated Stay" rows for any city but Lisbon, whose ids resolved nowhere, and the deprecated tourism_search hashed the destination and ignored budget. Both now read one catalogue (Lisbon, Porto, Barcelona, Nice, Bucharest) through one destination resolver that tolerates case, diacritics, aliases (Lisboa, Bucuresti) and City, Country; an unknown place is an honest empty result and every returned id resolves on details, photos, page, quote and availability. budget is a per-night EUR ceiling on both searches (another currency, or dates that are not an ISO range, are a 400). Both declare preferences (pets, breakfast, family; synonyms such as pet-friendly, cat, dog fold in, other tags are ignored), and wanderlust.Stay and wanderlust.StayDetails declare petPolicy. Adds a deterministic conversation suite and pnpm showcase:conversations, a local script that drives a live endpoint with a real model.

  • Models passed a stay's name where the showcase expects its id. Against the hosted demo a model called wanderlust_stay-photos with {"stayId":"Casa Alfama"} and got a bare 404, or asked the user for a city instead of searching by name. Every stay-id input in the showcase manifest now says it is the id field returned by wanderlust_search (like ws-1001), never a name, and that a stay the user names is found by calling wanderlust_search with that name as destination; the destination description says a stay's own name works. Declared descriptions only: the runtime and the ids are unchanged.

  • Showcase v2: a believable synthetic agency, and honest scenario cards (#201). Examples only; no Archstone guarantee changes. The synthetic agency now issues quotes and payment quotes that expire 15 minutes after the request (not at a fixed boundary), and book and pay refuse an expired one; wanderlust.quote takes an optional declared pets count and itemises the stay's pet fee in petFee and in the total the booking honours; a stay's exact name (diacritics and case folded) works as a destination on both searches; room-status is agency-busy / wrong-typed only on one property and date each; cancelling an id the agency never issued is 404 booking_not_found, and the seeded booking refunds its total. The blocked demo key is now denied by policy on pay and cancel as well as book. The scenario table gains S-23 (a wrong-shaped argument is refused before the agency is called), S-13 now also makes the wrong-format-price call, S-12 returns the tool-description excerpt it relies on, S-06/S-07 say which side enforces what, and the live /run body carries backendCalls.

  • The note that says a value was withheld now says exactly where, and that the rest is fine (#201, round 2). The origin-withholding note named only field names (url, photos[3]), so a model could read "the official page's link is withheld" when only a partner row's link was, and an original array index looked like a position in the shorter list it received. It now names each place in the result by the output field names the model sees, with the item's position in the provider's list as the index, pages[1].url (field omitted), and a removed list item reads gallery.photos[3] (removed; the list now has 4 items); the note ends "Every other link and image returned passed the origin check." (only links and images are origin-checked, so it claims no more) applyResponseMapping gains withheldAt (located paths) beside the unchanged withheld names, and withheldNote takes those locations. Nothing that was withheld before is now returned: the guarantee is unchanged. Showcase only: wanderlust.stay-page says a partner listing's link is withheld; wanderlust.cancel and wanderlust.pay say they need the agency key and an allowed principal; the booking carries pets and petFee (0 when none); and a stay's nightly rate is one figure across search, quote, room-status and availability.

  • The Showcase agency's two availability endpoints now agree (#201, round 3). wanderlust.room-status (per room type, free or taken) and wanderlust.availability (rooms free) were derived independently, so a date could read "both room types taken" in one and "4 rooms free" in the other, and a model could only call the date unconfirmed. Both now come from one deterministic count: 0 rooms free means every room-type row is taken, 1 means exactly one type is free, 2 or more means both are. Prices are unchanged. The two deliberate faults (the busy row on ws-1002, the wrong-typed price on ws-1003, both on 2027-05-12) stay, and the rows beside them agree with availability too. wanderlust.availability's description now says the call limit is Archstone's policy, 3 calls per minute per caller, rather than "Rate limited."

v0.32.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 10:21
Immutable release. Only release title and notes can be modified.
cbc69bf

0.30.0 and 0.31.0 were tagged but never published to npm. Their release gate failed on the
sql-reporting example's verify step (fixed below), so npm kept serving 0.29.0. Everything in the
[0.30.0] and [0.31.0] sections below therefore ships for the first time in 0.32.0, together
with the entries listed here.

Added

  • The Showcase has an executable negative-scenario suite. examples/showcase/test/ now asserts, through the real runtime and with a request spy around the synthetic API, what Archstone withholds and refuses: no margin, passport, phone or raw HTML reaches a model; an off-origin image or page link is withheld by field path and never fetched; each of the seven denial reasons is reached and a test fails if one is not; no tool exists for deletion and no DELETE is ever issued; and a hand-written passthrough double proves the absence checks cannot pass by accident. Examples and tests only; nothing in the published packages changes.

  • Recorded Showcase scenarios, examples/showcase S-15 to S-21. A recorder (pnpm showcase:record,
    pnpm showcase:record:check) runs the workspace CLI and the embedded SDK against the synthetic agency
    and writes one stable JSON transcript per scenario to examples/showcase/transcripts/: a SQL report from
    a local Postgres that the live manifest does not serve, apply --exposure, verify and adopt on a
    backend that gains a field, diff with the backend stopped, audit and doctor with no outbound
    connection (enforced by a preload that makes any attempt fail), init from the OpenAPI document, and the
    @archstone/agent SDK in three vendor shapes. Each scenario asserts its expected outcome and its
    negative and exits non-zero otherwise; --check fails CI on any byte that differs from a fresh
    recording. Examples and tests only: no published package changes.

  • A synthetic travel-agency example, examples/showcase. An invented agency whose backend
    deliberately over-exposes (guest passports and phones at several nesting levels, a private margin,
    raw HTML, images and links on undeclared hosts, a DELETE endpoint), and the CDL manifests that
    contain it: all three effects, every lifecycle state, authenticated with ${caller.accessToken},
    a principal allow/deny rule, a rate limit, onError rows, nested projection, and the image and
    web-page types with declared origins. It ships a mis-declared payment variant that archstone apply
    warns about without blocking, a scenario table (scenarios.json), two public demo keys, and tests
    that run the real pipeline against the API in-process. Examples and tests only: no published package
    changes.

Changed

  • Behaviour change: a backend that returns a bare number or string for a money field is no longer passed through. The value is now withheld (optional field, result degraded) or a contract_violation (required field). Declare such a field quantity if the backend really sends a plain number, or have the backend send {amount, currency}.

Fixed

  • archstone adopt could edit the wrong namespace's resource file. When two namespaces declared a resource with the same bare name (tourism.Stay and wanderlust.Stay), the lookup returned whichever document it met first, so a field adopted into wanderlust.search was written into tourism.Stay's file and the edit then failed to compile. An exact name now wins; the bare-name fallback is used only when exactly one resource matches, and an ambiguous one is reported as a problem naming every candidate.

  • archstone adopt resolved a namespace-qualified resource name into another namespace. When wanderlust.Foo had no exact match but exactly one resource elsewhere shared the bare name (tourism.Foo), the bare-name fallback picked that one and edited its file. A qualified name now never crosses namespaces: with no exact match, adopt reports no resource '<ns>.<Name>', lists same-bare-name resources as a hint, and writes nothing. The bare-name fallback still applies to unqualified names.

  • apply --exposure listed a retired capability as exposed. Each capability now carries a state (exposed, unlisted for an experimental one callable by id, or not_exposed with a reason of retired, unevaluatable or unbound), in the human report and in --json, which also gains a totals object. totals.exposed equals the number of tools tools/list advertises: both read the new Registry.listedTools(). (#173)

  • Extraction accepted any string as a money currency (#182). extractor(resource, format).validate() passed {amount: 10, currency: "euro"} (and "", "eur") as valid money, although the response path has required a finite numeric amount and a three-uppercase-letter currency since #176. Both paths now call one shared check, so they cannot disagree. In extraction a present but malformed money value is an invalid entry and the document a violation, as for every other malformed value (extraction never repairs, ADR-0011).

  • A money output field accepted a plain string as valid (#176). A value such as "price": "129.00" was passed on as if it were money. The mapper now requires an object with a finite numeric amount and a three-letter uppercase currency, and treats anything else as a shape mismatch: the field is withheld and the result degraded when it is optional, and a contract_violation when it is required, the same rule the other checked types follow.

  • The release gate now verifies the sql-reporting example instead of failing on it. It ran
    archstone verify on every example with only a mock URL in the environment, so the 0.31.0
    release stopped at isolation not verified: negative identity did not resolve to any claims.
    The gate now passes --identity-map to any example that ships an identity-map.json. For an
    example with a sql binding, it builds a database from the example's fixture.sql in the
    job's Postgres and connects as the fixture's runtime role, through the variable the binding's
    dsn names. If no database is configured, that example's verify fails rather than being
    skipped. Pull requests now run the same per-example build and verify against the workspace
    build, so an example that needs input the gate does not supply fails on its PR, not at
    release time (#162).

v0.29.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 18:54
Immutable release. Only release title and notes can be modified.
d9eee4b

Added

  • web-page, an Experimental output-only semantic type, checked against origins the binding
    declares.
    A link field typed string can carry any URL, so a provider's data — or text a
    listing's owner typed in — could have an assistant show a person a link to anywhere. A field
    typed web-page means "the page where a person sees this resource on the provider's own
    site", and a binding declares where such pages live with a new origins: { pages: [...] }
    key (a sibling of response:/extract:; each entry a bare https origin). The shared
    response mapper in @archstone/emitter-support (applyResponseMapping) now checks every
    web-page value — top-level, inside nested resources, in every collection row, in onError
    rows and in extract: fields — and fails closed: a value must be an absolute https URL with
    no userinfo whose normalised origin equals a declared one. A passing value is emitted as its
    normalised href; a failing one is withheld (an optional field is omitted and the result is
    degraded; a required field is a contract violation carried in _meta, never in
    structuredContent). MappingResult and @archstone/agent's ExecuteResult gain an
    optional withheld: string[] of field names — never values, and never added to degraded.
    archstone verify reports any withheld value red (value outside declared origins in: <fields>), and recording a contract keeps nothing when one is withheld. MCP lowers the type
    to { "type": "string", "format": "uri" }; the tools() envelopes carry input schemas only
    and are unchanged; extraction refuses it; archstone init never infers it. apply adds six
    named rules: web-page-in-input, web-page-no-origins, web-page-needs-mapping and
    origins-malformed (errors), origins-unused and web-page-required-in-collection
    (warnings). Additive: an IR without origins is byte-identical and IR.version stays "0".
    Only typed fields are checked (a URL inside a text field is untouched), relative links are
    withheld rather than resolved, and nothing fetches the page. See the CDL specification §4.7.

Changed

  • Breaking: what a manifest that under-declares a nested resource now returns. A mapped
    value contains only what its declared type names:

    • a nested resource value holds only the resource's declared fields, read by name, at every
      level and in every collection: row; other keys are dropped;
    • money, party and date-range objects keep only their declared keys. A primitive in their
      place (price: 120) passes as before;
    • a ref: slot takes a primitive id only. An object or array there is treated as absent,
      never reduced to an id;
    • an object or array where a scalar is declared is treated as absent, top level included;
    • nested values are capped at 32 resource levels; anything deeper is absent.

    Absent values follow the required/optional rules at each level. When a nested value is missing
    a required field, the nearest optional field above it is dropped and named in degraded
    (host, or host.agency deeper down). With no optional field on the way up, the response is
    a contract violation naming the deepest field (host.name; collection rows share a path, with
    no index). A collection: inside a resource is dropped as a whole when any row fails, never
    shortened. This also applies to a required web-page withheld inside a nested value. Until
    this release that failed the whole response even under an optional parent.

    archstone verify prints, under each capability,
    nested keys not declared (dropped): host.phone, …, with names only and never values. The
    line is informational and does not change the result. --json carries the same list as
    undeclaredNested. applyResponseMapping takes an optional fourth argument,
    { collectUndeclared: true }, which adds undeclaredNested to its result.

    Upgrading:

    1. Run archstone verify, declare on the nested resource each key it lists that you need, and
      re-run.
    2. If a binding uses @archstone/provider-sql and reads a date or timestamp column,
      re-record its fixture: those columns' contract fingerprints change from object to
      string (see below). Fingerprints of every other binding are unaffected.
    3. If you pass your own pgPoolFactory to @archstone/provider-sql, install its exported
      jsonSafeTypeParser on that pool (types: { getTypeParser: jsonSafeTypeParser }).
      Without it, date columns arrive as local-midnight Dates and shift by the host's
      time zone.
  • @archstone/provider-sql returns JSON-safe rows. pg returned date and timestamp
    columns as JS Date objects. The stricter mapper treats a non-JSON object as absent, so a
    required date field would fail the response. The default pool now parses a date as
    Postgres's own YYYY-MM-DD text, which also removes the one-day shift pg's local-midnight
    Date caused east or west of UTC. A timestamp (no time zone) is read as UTC and sent as an
    ISO instant (2026-10-03T12:34:56.789Z); a timestamptz is an ISO instant in UTC. Their array
    types are parsed the same way, and infinity or a BC value stays as Postgres prints it. Any
    value left with no JSON form is null, which the mapper treats as absent: bytea,
    interval, and other class instances. A required field read from such a column therefore
    reports missing. A bigint becomes its decimal string and a non-finite number becomes null.
    numeric and int8 already arrived as strings and are unchanged. A jsonb key named
    __proto__ is kept as ordinary data. The parser is exported as jsonSafeTypeParser.

  • archstone adopt records the replayed response against the manifest's own resources. It
    used to map that response with an empty resource registry, so every mapped field counted as
    required and no field type was known. It now uses the manifest's resource definitions: an
    absent optional field degrades (yellow) instead of failing the adoption, and a web-page
    value outside the declared origins stops it (red, field names only).

  • A shape error on an enumerated value now names the value it refused. @archstone/schema's
    loader appends (got "<value>") (JSON-quoted, truncated to 80 characters) to an enum
    failure in an authored manifest — e.g.
    /capability/output/links/list must be equal to one of the allowed values (got "web-page").
    Machine-emitted execution records are reported as before.

  • contractViolationMessage (@archstone/emitter-support) takes an optional third argument,
    the withheld field names.
    Without it, or with an empty list, the text is unchanged.

Security

  • @archstone/emitter-support: undeclared keys inside a nested value no longer reach the model
    (#146).
    The response mapper projected only the top level of each row. A field whose type is a
    resource (host: Host) was copied as the provider sent it, so every key inside it reached
    structuredContent, the model-facing text, the embedded execute() result and verify's
    replay, whether Host declared it or not. The same was true of a collection: inside a
    resource, of an object sent in a ref: slot, of extra keys inside a money, party or
    date-range object, and of an object or array sent where a plain scalar (text, quantity, …)
    is declared. Every value is now projected against its declared type at every level, so
    ADR-0008's guarantee, that an undeclared provider field never reaches a model, holds at any
    depth. Every earlier release is affected for an output resource that nests a type: resource,
    a collection: field or a composite semantic type.

v0.28.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 22:02
Immutable release. Only release title and notes can be modified.
19e7ef5

Changed

  • Breaking for a programmatic caller of ensureConnection or ConnectionEntry in
    @archstone/provider-sql.
    ensureConnection no longer runs the D-9 check. It is now
    synchronous and returns the pool with the DSN's cached refusal, if any ({ pool, entry, refusal? }, or { pool: undefined, error } when no pool could be created). The eager check
    that serve, serve --http and verify run at startup is the new checkConnectionPrivileges.
    ConnectionEntry.check is replaced by refusal and a per-server-and-database ownership map.
    invokeSql no longer checks out a separate connection for the check on its first call.

Fixed

  • archstone serve, serve --http and verify no longer call a sql connection over-privileged
    when the D-9 check could not reach a verdict.
    An unreachable database, a failed catalog query
    or a pg_postmaster_start_time() the runtime role cannot execute is now reported under
    sql connection privilege check(s) could not complete:, apart from a genuine refusal, which
    keeps over-privileged sql connection(s):. Both still exit 1. verify --json adds refused
    and incomplete arrays beside the existing errors (@archstone/cli). A CI script that
    matches verify --json's error === "sql_over_privileged" now sees
    sql_privilege_check_incomplete when no check reached a verdict and none refused; the exit code
    is unchanged, and errors still lists every finding, now refusals first. In
    @archstone/provider-sql, checkConnectionPrivileges marks a result that reached no verdict
    with incomplete: true (additive), and its no-verdict error now reads
    connection privilege check failed (…) instead of over-privileged connection check failed (…).

Security

  • A sql DSN re-pointed at another server kept the over-privileged verdict of the first one.
    @archstone/provider-sql ran the ADR-0012 D-9 role and ownership checks once per DSN and
    cached the result for the life of the process, so a long-lived serve --http or embedded
    execute() kept serving after a logical-replication failover, a blue/green cut-over or a proxy
    re-pointed behind the same DSN, onto a server where the role could be a superuser, hold
    BYPASSRLS or own what it reads. Now every transaction reads the role's rolsuper and
    rolbypassrls, the server's pg_postmaster_start_time() and the database oid before any claim
    is set. The ownership check runs again the first time a transaction lands on a server and
    database it has not judged. A refusal reached mid-life refuses every later call on that DSN
    until restart, as one at startup does. A read that fails, for example because the runtime role
    cannot execute pg_postmaster_start_time(), fails the call with query failed (…) and caches
    nothing; at serve and verify startup it stops the process. Not covered: an
    ALTER … OWNER TO or a new GRANT on the same server and database while the process runs
    (ADR-0012 R-8); restart long-lived processes after one.

v0.27.2

Choose a tag to compare

@github-actions github-actions released this 05 Oct 16:21
Immutable release. Only release title and notes can be modified.
f3b3319

Fixed

  • A connection pool that could not be created no longer prints its raw error at serve/verify
    startup.
    The ADR-0012 D-9 startup check echoed the pool factory's (or the pg Pool
    constructor's) own message unscrubbed, and that message can carry the DSN and its password.
    ensureConnection in @archstone/provider-sql no longer throws: a pool that cannot be created
    is a failed check, reported through the same path as every other driver failure — the error
    code only, with the DSN and its password scrubbed from the one stderr line — and is not cached,
    so the next call retries. The string for this case is now pool creation failed (…) at startup
    and at invocation; invocation previously said pool checkout failed (…).
    Terminal hygiene: the unscrubbed message never reached the model.

Security

  • @archstone/provider-sql could echo a literal DSN to the model. When a binding's dsn was
    not a ${VAR} reference, invokeSql used the DSN itself, password included, where the env var
    name belongs, and the over-privileged connection refusals (rolsuper, rolbypassrls, an owned
    relation) returned it to the caller. apply already refuses that shape, so this was reachable
    only past it. Now invokeSql refuses a non-${VAR} dsn before any connection is used, with an
    error that names no part of it, and the refusals from the exported ensureConnection name a
    DSN that is not an env var name as (unnamed dsn).

v0.27.1

Choose a tag to compare

@github-actions github-actions released this 05 Oct 10:59
Immutable release. Only release title and notes can be modified.
d55bdd0

Fixed

  • Published packages pointed repository.url at the old GitHub owner. The repository now lives at
    NousVigil/archstone, and npm rejects a provenance-signed publish whose package.json
    repository.url disagrees with the repository that built it (E422), so 0.27.0 could not be
    published. All nine packages now name https://github.com/NousVigil/archstone.git.
  • Links to the repository in the package READMEs, server.json, SECURITY.md, SUPPORT.md,
    CONTRIBUTING.md and the issue-template config now point at NousVigil/archstone.
  • The MCP Registry name moves to io.github.NousVigil/archstone. The registry verifies a
    namespace against the GitHub owner publishing it, which is now NousVigil. mcpName in
    @archstone/cli and name in server.json change together. Clients that pinned the old
    io.github.Archstone-Romania/archstone entry (last published at 0.26.0) must switch to the new name.

v0.26.0

Choose a tag to compare

@github-actions github-actions released this 30 Sep 10:47
Immutable release. Only release title and notes can be modified.
b06797f

Added

  • Two CI checks on the changelog, for contributors (.github/workflows/ci.yml). Every pull
    request now either adds a changelog.d/ fragment (or a line to CHANGELOG.md) or carries a
    Changelog: none — <reason> line in a commit message or its description
    (changelog entry or waiver, scripts/check-changelog-entry.mjs); and no pull request may
    change a released ## [x.y.z] section unless it declares
    Changelog-correction: <x.y.z> — <reason> (released changelog sections are unchanged,
    scripts/check-changelog-history.mjs). The second catches a silent failure: a branch that wrote
    under [Unreleased] before a release, rebased after it, has its entries reattached under the
    released heading by git with no conflict, so a shipped version appears to contain later work
    and the next release's notes lack it. See CONTRIBUTING.md → "The changelog". No change to
    any published package.

  • archstone init: an OpenAPI list of oneOf[success, error] rows now maps onto
    response.onError
    (@archstone/init, ADD-12 §8.1 / §8.4 item 1). When a list's items are a
    oneOf of two object branches and exactly one branch declares exactly one property with a
    scalar const, that branch is the error row: the binding gets
    onError: { errorResource: <Success>Error, when: { path: $.<property>, equals: <const> } },
    plus a map: only for a field whose source is not $.code / $.message, and a
    <Success>Error resource with the fields code and message is emitted beside the success
    resource. code reads from the error branch's code, else from the discriminator itself;
    message from its message, else from its one remaining plain string property. Such an
    operation used to be skipped as unsupported-composition. Every other two-branch oneOf is
    still refused, now under a reason code naming what is missing — oneof-too-many-branches,
    oneof-no-discriminator, oneof-non-object-branch, oneof-error-fields-unresolved — and the
    accepted form anywhere but the items of the collection being mapped (the response root, a
    single-object property, a nested list, or when the root locus is chosen) is refused as
    oneof-outside-collection rather than flattened into its success shape. anyOf, a
    discriminator keyword, and the nullability idiom (oneOf: [X, {type: 'null'}]) behave
    exactly as before.

  • Release prepare computes the version by default (bump: auto,
    scripts/classify-bump.mjs). It classifies the commits since the last v* tag by Conventional
    Commits — breaking, then feat, then everything else, counting every commit listed in a
    squash body — and names the commits that decided the bump in the run summary. Before 1.0 a
    breaking change bumps the minor, so a computed default never produces 1.0.0; patch / minor /
    major and an explicit version still override it. Maintainer tooling only.

v0.25.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 11:08
Immutable release. Only release title and notes can be modified.
f600ad2

Fixed

  • @archstone/provider-sql was left out of the release pipeline. providers/sql is
    private: false, but release.yml's hardcoded stamp-assert and publish loops did not list
    it. So the 0.24.0 stamp left it at 0.23.0, and CI never published it (its 0.23.0 and 0.24.0
    on npm were published by hand). It is now stamped in lockstep with the other packages.
    release.yml publishes it after the packages it depends on (@archstone/compiler,
    @archstone/emitter-support) and before its dependents (@archstone/runtime,
    @archstone/cli). The package counts in release.yml, release-prepare.yml,
    release-tag.yml and CONTRIBUTING.md now read nine.

  • @archstone/agent's "openai" format mixed two different OpenAI APIs' shapes
    (archstone#89). tools("openai")
    emitted the Chat Completions tool shape ({type, function:{name, description, parameters}}),
    while extractor(...,"openai").structuredOutput emitted the Responses API's text.format
    shape ({type, name, schema, strict}) — one Extractor handed a caller halves from two
    APIs that do not accept each other's shapes. ToolFormat now has two explicit values:
    "openai-chat" (Chat Completions: nested tool shape, response_format.json_schema for
    structured output) and "openai-responses" (Responses API: flat tool shape with
    strict: false, text.format for structured output). strict: false is unchanged on both
    — see extract.ts's header for why. "openai" remains a legal, @deprecated ToolFormat
    value and forwards to "openai-chat" on both axes.

Changed

  • Breaking, on the deprecated "openai" alias's structured-output axis only
    (archstone#89):
    extractor(resource, "openai").structuredOutput now returns the Chat Completions
    response_format.json_schema shape ({type, json_schema:{name, schema, strict}}) instead of
    the Responses API's flat text.format shape it returned before. tools("openai") is
    unchanged — byte-identical to tools("openai-chat"), as it was to pre-#89 tools("openai").
    A caller relying on extractor(..., "openai").structuredOutput's previous (Responses) shape
    must switch to "openai-responses" explicitly; a caller who only used tools("openai") is
    unaffected. OpenAIToolDef and OpenAIStructuredOutput are kept as @deprecated type
    aliases of the renamed OpenAIChatToolDef and OpenAIResponsesStructuredOutput so existing
    type-level imports do not break.

  • Changelog entries now go in changelog.d/, one file per change, instead of in
    CHANGELOG.md.
    Before, every PR added its entry at the top of the same [Unreleased]
    list, so almost every merge put the other open PRs in conflict. Release prepare now folds
    changelog.d/<slug>.<category>.md files into the version section and deletes them, and
    Release tag refuses a fragment merged after that step. CI also runs the release-script
    tests (node --test scripts/*.test.mjs) on every PR. Before, they ran only inside the
    release workflows, which is why the providers/sql omission surfaced at release time.
    See changelog.d/README.md.

v0.24.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 10:07
Immutable release. Only release title and notes can be modified.
67f51b0

Added

  • Row-level errors in a response: collection (@archstone/schema, @archstone/compiler,
    @archstone/emitter-support, ADD-12 §8.1, #81) — a response.onError block names a second,
    error-shaped resource and a when discriminator (path + equals/exists) that classifies
    each collection item before the success mapping runs. A matching row is mapped against
    errorResource and tagged $row: "error"; every other row is mapped against resource
    exactly as before, tagged $row: "ok", required fields enforced in full — a successful row is
    never loosened because another row in the same call failed. A row matching neither shape and
    missing a required field is a per-row violation, named and dropped from the returned array
    without implicating any other row. The whole-response contract_violation now fires only when
    a non-empty collection has zero usable rows. outputSchema for the mapped field advertises
    items: { oneOf: [<success, tagged>, <error, tagged>] } when onError is declared.
  • Scalar array fields outside the collection, via extract: (@archstone/emitter-support,
    ADD-12 §8.2, #82) — an output field declared as a List (list: <semantic type>) may now be
    populated by extract:: every JSONPath match becomes an array item instead of only the first,
    and an empty match set is OK, not DEGRADED. archstone adopt's planAdoption now offers an
    observed root-level (or otherwise outside-collection) array of one scalar type as adoptable;
    an observed array of objects is refused with a new, distinct reason
    (array-of-objects-unresolved), naming that it needs a declared row/resource shape core #49
    has not ratified yet.
  • Data-dependent array shapes no longer flap in archstone verify's drift report
    (@archstone/compiler, ADD-12 §8.3, #83) — diffShape now treats an array's element-level
    shape as observed-so-far: an array that goes from populated to empty no longer reports its
    element fields as removed, and one that goes from empty to populated no longer reports them
    as added. A genuinely new element variant (e.g. a declared onError error-row shape
    appearing for the first time) still reports as added, never folded into retyped; a field
    genuinely dropped while the array stays populated is still reported as removed.