Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .changeset/agent-code-is-the-record.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
---

docs(spec,metadata-protocol): record why platform `agent` definitions have no metadata change log (#4507)

Comment-only — no behaviour changes, nothing to release.

`agent` is the only authorable metadata type with no governed write path
(`allowOrgOverride` and `allowRuntimeCreate` are both `false` per ADR-0063 §2,
which closes `*.agent.ts` to third parties). Its rows are written by the
shipping plugin at boot — `AIStudioPlugin.registerMeta` → `metadataService.register()`
→ `MetadataManager.register` → `DatabaseLoader.save` — which writes
`sys_metadata` directly with a fresh checksum and appends no
`sys_metadata_history` row. So a shipped agent definition that changes between
releases leaves no metadata-side change log.

That is accepted rather than overlooked, and the reasoning now sits beside the
declaration instead of in an issue: the two definitions live in version control
(`@objectstack/service-ai-studio` in the `cloud` repo), so git already holds the
full reviewable history. A second history in `sys_metadata` would be a *worse*
record — it would capture only the boots where a given deployment happened to
see the checksum move, so two deployments on the same release would carry
different "histories" of an identical, code-fixed definition.

Two consequences that read as bugs and are not are named explicitly: the
`skipped` outcome `os migrate meta --stored` reports for `agent` rows is correct
and permanent for this type, and Studio showing no History tab for an agent is
the absence of anything to show. `migrateStoredMetadata`'s TSDoc now points at
the note rather than leaving its skip reason to be read as a to-do.

The note also states its own expiry: if `agent` is ever opened to tenant
authoring, an author-owned definition has no git to fall back on, so opening the
type and giving it a real history path become the same piece of work.
8 changes: 8 additions & 0 deletions packages/metadata-protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6610,6 +6610,14 @@ export class ObjectStackProtocolImplementation implements
* raw-engine branch, which records no history and forces `state:
* 'active'` — a historyless rewrite that could also promote a draft is
* not what this pass promises, so it declines instead.
*
* Today that is exactly one type, `agent`, and its skip is **permanent
* by design, not a to-do** (#4507): ADR-0063 §2 closes `*.agent.ts` to
* third parties, so the only agent definitions in existence are the two
* the platform ships from version control — where git, not
* `sys_metadata_history`, is the change log. See the note beside the
* `agent` entry in `metadata-plugin.zod.ts` before treating this branch
* as a gap to close.
* - **Rows that still fail the current schema after conversion.**
* `saveMetaItem` rejects them (422) and that rejection is correct: the
* body is a genuine contract violation, not chain-owned history. They
Expand Down
34 changes: 34 additions & 0 deletions packages/spec/src/kernel/metadata-plugin.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,40 @@ export const DEFAULT_METADATA_TYPE_REGISTRY: MetadataTypeRegistryEntry[] = [
// allowRuntimeCreate:false (no runtime "create agent") and
// allowOrgOverride:false (no per-org agent fork). The runtime catalog
// additionally filters out any non-platform agent record (see service-ai).
//
// FOR AGENTS, THE CODE IS THE RECORD — and that is the whole answer to
// "where is this type's change log?" (#4507). Because the two flags above
// are false, `agent` is the one authorable type with NO governed write
// path: `saveMetaItem` would route it down the legacy raw-engine branch,
// and nothing calls it. The rows are written instead by the shipping
// plugin at boot — `AIStudioPlugin.registerMeta` → `metadataService
// .register()` → `MetadataManager.register` → `DatabaseLoader.save` —
// which writes `sys_metadata` directly with a fresh checksum and appends
// NO `sys_metadata_history` row. So an agent definition that changes
// between releases leaves no metadata-side change log, and there is no
// metadata-side rollback.
//
// That is accepted, not overlooked. These definitions live in version
// control (`@objectstack/service-ai-studio`, `cloud` repo:
// `agents/ask-agent.ts`, `agents/metadata-assistant-agent.ts`), so git
// already holds the full, reviewable history of every change. A second
// history in `sys_metadata` would be a WORSE record, not a better one: it
// would capture only the boots where a given deployment happened to see
// the checksum move, so two deployments on the same release would carry
// different "histories" of an identical, code-fixed definition. Do not add
// one to close a perceived gap.
//
// Two consequences that look like bugs and are not:
// - `migrateStoredMetadata` reports `agent` rows `skipped` ("no repository
// write path"). That is CORRECT AND PERMANENT for this type, not a
// to-do — the pass declines rather than performing a historyless
// rewrite that could also promote a draft.
// - Studio surfaces no History tab for an agent. There is nothing to show;
// the answer to "what changed" is the `cloud` commit log.
//
// If `agent` is ever OPENED to tenant authoring, this note stops applying:
// an author-owned definition has no git to fall back on, so opening the
// type and giving it a real history path are the same piece of work.
{ type: 'agent', label: 'AI Agent', filePatterns: ['**/*.agent.ts', '**/*.agent.yml'], supportsOverlay: false, allowOrgOverride: false, allowRuntimeCreate: false, supportsVersioning: true, executionPinned: true, loadOrder: 90, domain: 'ai' },
{ type: 'tool', label: 'AI Tool', filePatterns: ['**/*.tool.ts', '**/*.tool.yml'], supportsOverlay: true, allowOrgOverride: true, allowRuntimeCreate: true, supportsVersioning: false, executionPinned: false, loadOrder: 85, domain: 'ai' },
{ type: 'skill', label: 'AI Skill', filePatterns: ['**/*.skill.ts', '**/*.skill.yml'], supportsOverlay: true, allowOrgOverride: true, allowRuntimeCreate: true, supportsVersioning: false, executionPinned: false, loadOrder: 88, domain: 'ai' },
Expand Down
Loading