diff --git a/.changeset/13272-liveness-cloud-citations-verifiedat-anchors.md b/.changeset/13272-liveness-cloud-citations-verifiedat-anchors.md new file mode 100644 index 00000000000..f6b78fb4a25 --- /dev/null +++ b/.changeset/13272-liveness-cloud-citations-verifiedat-anchors.md @@ -0,0 +1,14 @@ +--- +"@objectstack/spec": patch +--- + +`liveness/agent.json`, `liveness/skill.json` and `liveness/action.json` — the 21 cloud citations these ledgers rest on now carry the date they were read and the symbol they were read at, and the two claims that reading falsified are corrected in the prose (#13272). + +The ledgers ship inside this package, so the pointers an upgrading reader follows are these. Until now they named a package root and nothing else: `cloud: packages/service-ai/src/agent-runtime.ts`, with no date and — after #13309 repointed them off a path that existed in neither repository — still no evidence that anybody had opened the file. Every row was re-read in a cloud checkout at cloud `@cb8ee7ff60c097cc21a584fe9caf8ef4391cc0e8` and now carries `verifiedAt: 2026-09-15`, `evidenceScope: "cross-repo"`, and a `#symbol` anchor on the consuming function. + +- **A symbol instead of a line, because a line rots in range.** Three of the cited line numbers had already drifted onto unrelated prose (`agent-runtime.ts:264`, `agent-access.ts:50`, `action-tools.ts:535`) while every mechanical check kept passing. A symbol moves with the consumer and goes red when the consumer is renamed or deleted. +- **The framework half is now gate-checked.** `packages/mcp/src/skill-prompts.ts#projectSkillPrompt` is a repo-local anchor in five skill rows — the `;` before it ends the `cloud` realm's scope — so `check:liveness` resolves it against the file on every run, where the old parenthesised `(projectSkillPrompt)` was prose no check read. Cloud anchors are counted, never resolved, which is why the date on them is load-bearing. +- **Two ledger assertions were false and are repaired.** `agent.role` was noted as *"persona → system prompt."*: it reaches `AgentSummary` through `listAgents` and nothing else — `buildSystemMessages` never reads it. `agent.planning` was cited at `agent-runtime.ts`, which does not read the key at all; its three readers are `routes/agent-routes.ts`, `routes/assistant-routes.ts` and `eval/eval-runner.ts`. +- **One row is deliberately left unstamped.** `agent.tools` was falsified by the same read — zero consumers in cloud, and this package's own `AgentSchema` already declares the key `retiredKey(...)`. Its verdict is a liveness re-grade rather than a stamping decision, filed separately as #18304; a `verifiedAt` there would certify the wrong thing. + +No verdict moved and no schema changed: this is the evidence layer of the ledger, and `check:liveness` reports the same 505 repo-local paths resolving as before with five more anchors now checked. diff --git a/packages/spec/liveness/action.json b/packages/spec/liveness/action.json index 41930a31d47..82b592d8db0 100644 --- a/packages/spec/liveness/action.json +++ b/packages/spec/liveness/action.json @@ -1,6 +1,6 @@ { "type": "action", - "_note": "ActionSchema. Seeded from docs/audits/2026-06-actionschema-property-liveness.md. Renderers live in objectui (evidence cited as prose, not framework paths); framework-side: service-ai action-tools, runtime body-runner/http-dispatcher. Containers (params/resultDialog/ai/aria) classified at top level — no divergent sub-statuses in the audit. ⚠ EVIDENCE LIVES IN CLOUD/EE: the `cloud: packages/service-ai/...` paths cited below are the closed `@objectstack/service-ai` runtime in the CLOUD repo, NOT git-tracked framework code. 2026-08-30 (#13272): the previous wording of this sentence was false in BOTH halves. (a) It called the framework's own service-ai tree “a stale build artifact with no src/” — there is no tree at all: `packages/services/` holds every sibling service EXCEPT service-ai, and `git ls-files | grep -ic service-ai` returns 0. Absent, not stale. (b) The citations spelled `packages/services/service-ai/...`, a path present in NEITHER repo; cloud's real layout, measured at cloud@15f55df (#13042), is `packages/service-ai/...`. Every citation below now carries the explicit `cloud` realm marker, so it is attributed by the marker `scanEvidence` reads rather than riding the `FOREIGN_PATH_PREFIXES` special case that silently exempted the stale spelling from resolution — which is why 22 dead pointers sat green. ⚠ NOT RE-VERIFIED: this repair corrected the package root from that recorded measurement ONLY. No consumer below was re-read against a cloud checkout, so no `verifiedAt` was stamped and no `#symbol` anchor was added — the gate never resolves a foreign anchor, so an unchecked one would re-create the unfalsifiable pointer this repair removes. Re-verifying these consumers against a live cloud checkout is still open (#13272). These props are `live` because that cloud runtime consumes them; the OPEN framework edition does not — see content/docs/ai for the open/cloud boundary. 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent.", + "_note": "ActionSchema. Seeded from docs/audits/2026-06-actionschema-property-liveness.md. Renderers live in objectui (evidence cited as prose, not framework paths); framework-side: service-ai action-tools, runtime body-runner/http-dispatcher. Containers (params/resultDialog/ai/aria) classified at top level — no divergent sub-statuses in the audit. ⚠ EVIDENCE LIVES IN CLOUD/EE: the `cloud @: packages/service-ai/...` paths cited below are the closed `@objectstack/service-ai` runtime in the CLOUD repo, NOT git-tracked framework code. 2026-08-30 (#13272): the previous wording of this sentence was false in BOTH halves. (a) It called the framework's own service-ai tree “a stale build artifact with no src/” — there is no tree at all: `packages/services/` holds every sibling service EXCEPT service-ai, and `git ls-files | grep -ic service-ai` returns 0. Absent, not stale. (b) The citations spelled `packages/services/service-ai/...`, a path present in NEITHER repo; cloud's real layout, measured at cloud@15f55df (#13042), is `packages/service-ai/...`. Every citation below now carries the explicit `cloud` realm marker, so it is attributed by the marker `scanEvidence` reads rather than riding the `FOREIGN_PATH_PREFIXES` special case that silently exempted the stale spelling from resolution — which is why 22 dead pointers sat green. ✅ RE-VERIFIED 2026-09-15 (#13272): the re-verification half this entry parked is discharged. All three cloud consumers cited below were re-read in a cloud checkout at cloud @cb8ee7ff60c097cc21a584fe9caf8ef4391cc0e8 and all three are CONFIRMED; every row now carries `verifiedAt`, `evidenceScope: cross-repo`, and `#symbol` anchors pinned to the consuming functions instead of a line number — the one cited line (`action-tools.ts:535`) had already drifted to 545 in a 961-line file that is actively edited. The anchors are the load-bearing half, and they are why the DATE matters: `scanEvidence` never collects an anchor while a foreign realm marker is in force, so CI cannot re-derive a single one of the cloud anchors — each rests on that dated reading alone. ⛔ Never re-stamp `verifiedAt` here without re-reading cloud; a bare re-stamp restores exactly the unfalsifiable pointer this entry's history is made of. These props are `live` because that cloud runtime consumes them; the OPEN framework edition does not — see content/docs/ai for the open/cloud boundary. 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent.", "props": { "name": { "status": "live", @@ -18,7 +18,9 @@ }, "objectName": { "status": "live", - "evidence": "cloud: packages/service-ai/src/tools/action-tools.ts:535", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#buildParametersSchema — materialises the record-id parameter and its description for a row-context action; cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#actionToToolDefinition — carried onto the tool definition; cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#createActionToolHandler — the object the invocation targets.", "note": "action dispatch + AI bridge." }, "icon": { @@ -81,7 +83,9 @@ }, "params": { "status": "live", - "evidence": "cloud: packages/service-ai/src/tools/action-tools.ts", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#buildParametersSchema — each declared param becomes one JSON Schema property on the exposed tool.", "note": "field/objectOverride/defaultFromRow/options/placeholder/helpText/defaultValue/required all consumed." }, "variant": { @@ -141,7 +145,9 @@ }, "ai": { "status": "live", - "evidence": "cloud: packages/service-ai/src/tools/action-tools.ts", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#actionToToolDefinition — ai.exposed is the gate, and ai.category plus ai.outputSchema ride onto the definition; cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#actionRequiresApproval — ai.requiresConfirmation overrides the destructive-by-default rule; cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#actionSkipReason — refuses an unexposed or undescribed action; cloud @cb8ee7ff: packages/service-ai/src/tools/action-tools.ts#buildParametersSchema — ai.paramHints annotate the generated schema.", "note": "full AI bridge (exposed/description/category/paramHints/outputSchema/requiresConfirmation)." }, "recordIdParam": { diff --git a/packages/spec/liveness/agent.json b/packages/spec/liveness/agent.json index 0753f616b88..8c051fcc176 100644 --- a/packages/spec/liveness/agent.json +++ b/packages/spec/liveness/agent.json @@ -1,14 +1,18 @@ { "type": "agent", - "_note": "AgentSchema. Seeded from docs/audits/2026-06-agentschema-property-liveness.md. agent-runtime.ts is the runtime consumer; AgentPreview is display-only. ⚠ EVIDENCE LIVES IN CLOUD/EE: the `cloud: packages/service-ai/...` paths cited below are the closed `@objectstack/service-ai` runtime in the CLOUD repo, NOT git-tracked framework code. 2026-08-30 (#13272): the previous wording of this sentence was false in BOTH halves. (a) It called the framework's own service-ai tree “a stale build artifact with no src/” — there is no tree at all: `packages/services/` holds every sibling service EXCEPT service-ai, and `git ls-files | grep -ic service-ai` returns 0. Absent, not stale. (b) The citations spelled `packages/services/service-ai/...`, a path present in NEITHER repo; cloud's real layout, measured at cloud@15f55df (#13042), is `packages/service-ai/...`. Every citation below now carries the explicit `cloud` realm marker, so it is attributed by the marker `scanEvidence` reads rather than riding the `FOREIGN_PATH_PREFIXES` special case that silently exempted the stale spelling from resolution — which is why 22 dead pointers sat green. ⚠ NOT RE-VERIFIED: this repair corrected the package root from that recorded measurement ONLY. No consumer below was re-read against a cloud checkout, so no `verifiedAt` was stamped and no `#symbol` anchor was added — the gate never resolves a foreign anchor, so an unchecked one would re-create the unfalsifiable pointer this repair removes. Re-verifying these consumers against a live cloud checkout is still open (#13272). These props are `live` because that cloud runtime consumes them; the OPEN framework edition does not — see content/docs/ai for the open/cloud boundary. 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent. agent.knowledge (and AIKnowledgeSchema) removed; the topics→sources rename was absorbed into the removal pre-release.", + "_note": "AgentSchema. Seeded from docs/audits/2026-06-agentschema-property-liveness.md. agent-runtime.ts is the PRINCIPAL runtime consumer, not the only one: `routes/agent-routes.ts`, `routes/assistant-routes.ts`, `routes/agent-access.ts` and `eval/eval-runner.ts` each read keys classified here, and `planning` is read in three of those and in agent-runtime.ts NOT AT ALL — the citation this entry carried for it named the wrong file until 2026-09-15 (#13272). AgentPreview is display-only. ⚠ EVIDENCE LIVES IN CLOUD/EE: the `cloud @: packages/service-ai/...` paths cited below are the closed `@objectstack/service-ai` runtime in the CLOUD repo, NOT git-tracked framework code. 2026-08-30 (#13272): the previous wording of this sentence was false in BOTH halves. (a) It called the framework's own service-ai tree “a stale build artifact with no src/” — there is no tree at all: `packages/services/` holds every sibling service EXCEPT service-ai, and `git ls-files | grep -ic service-ai` returns 0. Absent, not stale. (b) The citations spelled `packages/services/service-ai/...`, a path present in NEITHER repo; cloud's real layout, measured at cloud@15f55df (#13042), is `packages/service-ai/...`. Every citation below now carries the explicit `cloud` realm marker, so it is attributed by the marker `scanEvidence` reads rather than riding the `FOREIGN_PATH_PREFIXES` special case that silently exempted the stale spelling from resolution — which is why 22 dead pointers sat green. ✅ RE-VERIFIED 2026-09-15 (#13272): the re-verification half this entry parked is discharged. Every cloud consumer cited below was re-read in a cloud checkout at cloud @cb8ee7ff60c097cc21a584fe9caf8ef4391cc0e8, and the ten rows the read confirmed now carry `verifiedAt`, `evidenceScope: cross-repo`, and a `#symbol` anchor pinned to the consumer instead of a line number — the two cited line numbers (`agent-runtime.ts:264`, `agent-access.ts:50`) had both drifted onto prose, which is the rot a line citation produces and a symbol does not. The anchors are the load-bearing half, and they are why the DATE matters: `scanEvidence` never collects an anchor while a foreign realm marker is in force, so CI cannot re-derive a single one of the cloud anchors — each rests on that dated reading alone. ⛔ Never re-stamp `verifiedAt` here without re-reading cloud; a bare re-stamp restores exactly the unfalsifiable pointer this entry's history is made of. ⛔ ONE ROW IS DELIBERATELY NOT STAMPED. `tools` was FALSIFIED by the same read: zero consumers in cloud at that ref, where the only two mentions are comments recording the removal of the branch, while this repo's own AgentSchema already declares the key `retiredKey(...)`. A `verifiedAt` there would certify the wrong thing, so the row keeps its `status`, its `note` and its old evidence untouched; the liveness re-grade is triage's to make and is filed as #18304. Note the shape — that row sat `live` since the 2026-06 audit BECAUSE `FOREIGN_PATH_PREFIXES` exempted its citation from resolution, so the exemption this card was filed about had hidden a dead key, not only a misspelled path. These props are `live` because that cloud runtime consumes them; the OPEN framework edition does not — see content/docs/ai for the open/cloud boundary. 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent. agent.knowledge (and AIKnowledgeSchema) removed; the topics→sources rename was absorbed into the removal pre-release.", "props": { "name": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#listAgents — the catalog gates platform ownership on this name and projects it as the AgentSummary identity; cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#loadAgent — the same gate on the single-agent path." }, "surface": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts (resolveActiveSkills)", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#resolveActiveSkills — ADR-0064 3 affinity: a skill binds only to an agent whose surface it matches, or declares both; cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#buildRequestOptions — the build surface alone gets reasoningEffort.", "note": "ADR-0063 §1 — the product surface this agent binds ('ask'|'build'). resolveActiveSkills enforces that only surface-compatible skills (matching, or 'both') attach; tool scoping is derived from that bundle." }, "label": { @@ -21,22 +25,30 @@ }, "role": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts", - "note": "persona → system prompt." + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#listAgents — projected into AgentSummary for the picker, and that is the ONLY production read. NOT the system prompt: buildSystemMessages pushes instructions, the date block, UI context and the skills block, never role.", + "note": "persona → the AgentSummary the agent picker renders. ⚠ 2026-09-15 (#13272): the previous wording of this note — \"persona → system prompt.\" — is FALSIFIED. Read at cloud @cb8ee7ff: `listAgents` projects `role` onto AgentSummary and that is its ONLY production read, while `buildSystemMessages` pushes `instructions`, the date block, the UI context and the skills block, and never `role`. The verdict is unmoved — the key is live on that projection — but nothing about it reaches the model." }, "instructions": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#buildSystemMessages — pushed first into the system message.", "note": "system prompt." }, "model": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts:264", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#buildRequestOptions — applies model, temperature and maxTokens onto AIRequestOptions; model.provider and topP have no reader anywhere in cloud.", "note": "PARTIAL — model/temperature/maxTokens applied; model.provider + topP DEAD." }, "skills": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#resolveActiveSkills — the name list handed to SkillRegistry.listActiveSkills, and the only tool-bearing slot under ADR-0064.", "note": "Agent→Skill→Tool." }, "tools": { @@ -46,23 +58,31 @@ }, "active": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#listAgents — an inactive record never enters the catalog; cloud @cb8ee7ff: packages/service-ai/src/routes/agent-routes.ts#buildAgentRoutes — chat answers 403 PERMISSION_DENIED with reason \"is not active\"; cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#resolveDefaultAgent — an inactive agent is never the ambient default.", "note": "gates listing + 403 on chat." }, "planning": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts", + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/routes/agent-routes.ts#buildAgentRoutes — reads agent.planning?.maxIterations into the turn options; cloud @cb8ee7ff: packages/service-ai/src/routes/assistant-routes.ts#buildAssistantRoutes — same read on the assistant path; cloud @cb8ee7ff: packages/service-ai/src/eval/eval-runner.ts#EvalRunner — same read in the eval harness. agent-runtime.ts does NOT read planning.", "note": "Only planning.maxIterations remains; the dead strategy/allowReplan knobs were removed in 16.0 (#2377)." }, "access": { "status": "live", - "evidence": "cloud: packages/service-ai/src/routes/agent-access.ts:50", - "note": "evaluateAgentAccess() — allow-list by userId/role; enforced at the chat route (agent-routes.ts:151). #1884 (landed after the 2026-06 audit, which still listed it dead)." + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/routes/agent-access.ts#evaluateAgentAccess — the allow-list; a caller matches by userId or by a held position, otherwise chat is refused and the listing drops the agent.", + "note": "evaluateAgentAccess() — allow-list by userId or by a held POSITION; two enforcement points, not one: the chat route routes/agent-routes.ts#buildAgentRoutes answers 403, and the catalog agent-runtime.ts#listAgents drops an inaccessible agent SILENTLY. #1884, landed after the 2026-06 audit which still listed it dead. ⚠ 2026-09-15 (#13272): the previous wording of this note — \"allow-list by userId/role; enforced at the chat route (agent-routes.ts:151)\" — is FALSIFIED in BOTH halves, measured at cloud @cb8ee7ff. (a) `roles` is the alias protocol 17 removed from the producer's envelope (framework #6011), after which `user.roles ?? []` degraded to the empty set — the cloud#1442 outage. `user.roles` now occurs ONCE in agent-access.ts, inside the docblock recording its removal, while `user.positions` is the live read, twice, both executable. (b) agent-routes.ts:151 now holds an unrelated ADR-0013 conversation-history guardrail; the chat-route call sits at :494. ⚠ And the single-enforcement-point framing was the more costly half: it teaches that an agent missing from the picker is a DIFFERENT bug from a 403, when agent-access-lint.ts:14 names exactly this asymmetry — \"two consumers with two denial shapes\"." }, "permissions": { "status": "live", - "evidence": "cloud: packages/service-ai/src/routes/agent-access.ts:50", - "note": "evaluateAgentAccess() — caller must hold ALL required permissions/roles; enforced at the chat route. #1884." + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/routes/agent-access.ts#evaluateAgentAccess — every named permission must be held; the check is fail-closed on a caller with no userId.", + "note": "evaluateAgentAccess() — the caller must hold ALL required entries, matched against the union of user.permissions and user.positions; same two enforcement points as access. ⚠ 2026-09-15 (#13272): the previous wording — \"caller must hold ALL required permissions/roles; enforced at the chat route.\" — is FALSIFIED, measured at cloud @cb8ee7ff. `roles` is the alias protocol 17 removed from the producer's envelope (framework #6011), and what can satisfy a required entry is a permission or a POSITION name, never a role. The chat route is one of the two enforcement points, not the only one." }, "lifecycle": { "status": "experimental", diff --git a/packages/spec/liveness/skill.json b/packages/spec/liveness/skill.json index 2ee57609a88..50e2209de6f 100644 --- a/packages/spec/liveness/skill.json +++ b/packages/spec/liveness/skill.json @@ -1,54 +1,62 @@ { "type": "skill", - "_note": "SkillSchema. Seeded from docs/audits/2026-06-skillschema-property-liveness.md. skill-registry.ts + agent-runtime.ts are the runtime consumers. ⚠ EVIDENCE LIVES IN CLOUD/EE: the `cloud: packages/service-ai/...` paths cited below are the closed `@objectstack/service-ai` runtime in the CLOUD repo, NOT git-tracked framework code. 2026-08-30 (#13272): the previous wording of this sentence was false in BOTH halves. (a) It called the framework's own service-ai tree “a stale build artifact with no src/” — there is no tree at all: `packages/services/` holds every sibling service EXCEPT service-ai, and `git ls-files | grep -ic service-ai` returns 0. Absent, not stale. (b) The citations spelled `packages/services/service-ai/...`, a path present in NEITHER repo; cloud's real layout, measured at cloud@15f55df (#13042), is `packages/service-ai/...`. Every citation below now carries the explicit `cloud` realm marker, so it is attributed by the marker `scanEvidence` reads rather than riding the `FOREIGN_PATH_PREFIXES` special case that silently exempted the stale spelling from resolution — which is why 22 dead pointers sat green. ⚠ NOT RE-VERIFIED: this repair corrected the package root from that recorded measurement ONLY. No consumer below was re-read against a cloud checkout, so no `verifiedAt` was stamped and no `#symbol` anchor was added — the gate never resolves a foreign anchor, so an unchecked one would re-create the unfalsifiable pointer this repair removes. Re-verifying these consumers against a live cloud checkout is still open (#13272). 2026-08-06 (#3905): that used to be the WHOLE story — the open framework consumed nothing here. It now consumes the INSTRUCTIONS half: `packages/mcp/src/skill-prompts.ts` projects every active skill carrying `instructions` onto the MCP `prompts` primitive (name/label/description/instructions/active are read there, in-repo and testable). The TOOL-BINDING half (`tools`, `surface`, `triggerConditions`) stays cloud-runtime-only and now says so in the schema's own JSDoc. See content/docs/ai for the open/cloud boundary. 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent.", + "_note": "SkillSchema. Seeded from docs/audits/2026-06-skillschema-property-liveness.md. skill-registry.ts + agent-runtime.ts are the runtime consumers. ⚠ EVIDENCE LIVES IN CLOUD/EE: the `cloud @: packages/service-ai/...` paths cited below are the closed `@objectstack/service-ai` runtime in the CLOUD repo, NOT git-tracked framework code. 2026-08-30 (#13272): the previous wording of this sentence was false in BOTH halves. (a) It called the framework's own service-ai tree “a stale build artifact with no src/” — there is no tree at all: `packages/services/` holds every sibling service EXCEPT service-ai, and `git ls-files | grep -ic service-ai` returns 0. Absent, not stale. (b) The citations spelled `packages/services/service-ai/...`, a path present in NEITHER repo; cloud's real layout, measured at cloud@15f55df (#13042), is `packages/service-ai/...`. Every citation below now carries the explicit `cloud` realm marker, so it is attributed by the marker `scanEvidence` reads rather than riding the `FOREIGN_PATH_PREFIXES` special case that silently exempted the stale spelling from resolution — which is why 22 dead pointers sat green. ✅ RE-VERIFIED 2026-09-15 (#13272): the re-verification half this entry parked is discharged. All eight cloud consumers cited below were re-read in a cloud checkout at cloud @cb8ee7ff60c097cc21a584fe9caf8ef4391cc0e8 and all eight are CONFIRMED; every row now carries `verifiedAt`, `evidenceScope: cross-repo`, and a `#symbol` anchor instead of a line number. The `verifiedAt: 2026-08-06` these eight used to carry was worse than no stamp at all — it was taken while the citation still named `packages/services/service-ai/…`, a path present in NEITHER repo, so it was false confidence that the 180-day staleness clock in verification.mts is structurally unable to see: 40 days old, never flagged, resting on nothing. The anchors are the load-bearing half, and they are why the DATE matters: `scanEvidence` never collects an anchor while a foreign realm marker is in force, so CI cannot re-derive a single one of the cloud anchors — each rests on that dated reading alone. ⛔ Never re-stamp `verifiedAt` here without re-reading cloud; a bare re-stamp restores exactly the unfalsifiable pointer this entry's history is made of. The FRAMEWORK half is the one CI can falsify, and it is now written so it does: `packages/mcp/src/skill-prompts.ts#projectSkillPrompt` sits after a `;`, which ends the cloud realm's scope, so the anchor is LOCAL and `checkEvidenceAnchors` resolves it against the file on every run — where the old parenthesised `(projectSkillPrompt)` was prose the gate never read. ⚠ `instructions` used to cite `(skillPromptResult)`, one hop too far downstream: that function consumes the PROJECTED value, while the record's own `instructions` key is read in `projectSkillPrompt`, which is what the anchor now names. 2026-08-06 (#3905): that used to be the WHOLE story — the open framework consumed nothing here. It now consumes the INSTRUCTIONS half: `packages/mcp/src/skill-prompts.ts` projects every active skill carrying `instructions` onto the MCP `prompts` primitive (name/label/description/instructions/active are read there, in-repo and testable). The TOOL-BINDING half (`tools`, `surface`, `triggerConditions`) stays cloud-runtime-only and now says so in the schema's own JSDoc. See content/docs/ai for the open/cloud boundary. 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent.", "props": { "name": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts; packages/mcp/src/skill-prompts.ts (projectSkillPrompt)", - "note": "also the MCP prompt name in the open framework (#3905).", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#composeInstructionsBlock — heads the skill's block in the system prompt; cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#toSummary — the wire identity; cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#listActiveSkills — matched against the agent's allow-list; packages/mcp/src/skill-prompts.ts#projectSkillPrompt — the MCP prompt id, and a row with no name is dropped.", + "note": "also the MCP prompt name in the open framework (#3905)." }, "surface": { "status": "live", - "evidence": "cloud: packages/service-ai/src/agent-runtime.ts (resolveActiveSkills)", - "note": "ADR-0063 §3 / ADR-0064 — skill↔agent affinity. resolveActiveSkills hard-fails when a bound skill's surface ('ask'|'build'|'both') is incompatible with the agent's surface; the union of surface-compatible skills' tools IS the agent's tool set (no global fall-through). CLOUD-RUNTIME-ONLY (#3905) — the open framework has no agent to bind to.", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/agent-runtime.ts#resolveActiveSkills — ADR-0064 3 affinity, checked against the agent's surface; both binds to either.", + "note": "ADR-0063 §3 / ADR-0064 — skill↔agent affinity. resolveActiveSkills hard-fails when a bound skill's surface ('ask'|'build'|'both') is incompatible with the agent's surface; the union of surface-compatible skills' tools IS the agent's tool set (no global fall-through). CLOUD-RUNTIME-ONLY (#3905) — the open framework has no agent to bind to." }, "label": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts:247; packages/mcp/src/skill-prompts.ts (projectSkillPrompt)", - "note": "injected into the agent system prompt (cloud); the MCP prompt `title` in the open framework (#3905).", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#composeInstructionsBlock — the block heading the model reads; cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#toSummary — the palette label; packages/mcp/src/skill-prompts.ts#projectSkillPrompt — becomes the MCP prompt title.", + "note": "injected into the agent system prompt (cloud); the MCP prompt `title` in the open framework (#3905)." }, "description": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts:247; packages/mcp/src/skill-prompts.ts (projectSkillPrompt)", - "note": "injected into prompt (cloud); the MCP prompt `description` in the open framework (#3905).", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#composeInstructionsBlock — emitted under the heading when present; cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#toSummary — the palette description; packages/mcp/src/skill-prompts.ts#projectSkillPrompt — becomes the MCP prompt description.", + "note": "injected into prompt (cloud); the MCP prompt `description` in the open framework (#3905)." }, "instructions": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts:247; packages/mcp/src/skill-prompts.ts (skillPromptResult)", - "note": "injected into prompt (cloud); served as the MCP `prompts/get` message body in the open framework (#3905) — a skill without it is not projected at all.", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#composeInstructionsBlock — appended to the agent's system prompt; packages/mcp/src/skill-prompts.ts#projectSkillPrompt — the required half: a row without instructions is dropped, and skillPromptResult then carries the projected text as the prompt's one message.", + "note": "injected into prompt (cloud); served as the MCP `prompts/get` message body in the open framework (#3905) — a skill without it is not projected at all." }, "tools": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts:206", - "note": "tool-contribution path incl. action_* wildcard. CLOUD-RUNTIME-ONLY (#3905): MCP exposes one flat tool list to a client-side model, so there is nothing to bind server-side; still validated at authoring time in both distributions.", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#flattenToTools — resolved against the registered tool set, with a trailing star subscribing to a family such as action_*; cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#composeInstructionsBlock — also listed to the model by name.", + "note": "tool-contribution path incl. action_* wildcard. CLOUD-RUNTIME-ONLY (#3905): MCP exposes one flat tool list to a client-side model, so there is nothing to bind server-side; still validated at authoring time in both distributions." }, "triggerConditions": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts:153", - "note": "THE activation gate — AND of {field,operator,value}. CLOUD-RUNTIME-ONLY (#3905): MCP has no server-side activation step; a client lists every projected prompt and chooses.", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#matchesContext — each condition is evaluated against the turn's SkillContext, and a skill that fails is not attached.", + "note": "THE activation gate — AND of {field,operator,value}. CLOUD-RUNTIME-ONLY (#3905): MCP has no server-side activation step; a client lists every projected prompt and chooses." }, "active": { "status": "live", - "evidence": "cloud: packages/service-ai/src/skill-registry.ts:93; packages/mcp/src/skill-prompts.ts (projectSkillPrompt)", - "note": "inactive skills dropped — by the cloud registry, and not projected as an MCP prompt either (#3905).", - "verifiedAt": "2026-08-06" + "verifiedAt": "2026-09-15", + "evidenceScope": "cross-repo", + "evidence": "cloud @cb8ee7ff: packages/service-ai/src/skill-registry.ts#listSkills — an inactive record never enters the pool that listActiveSkills filters; packages/mcp/src/skill-prompts.ts#projectSkillPrompt — an inactive row is dropped from the MCP prompt list.", + "note": "inactive skills dropped — by the cloud registry, and not projected as an MCP prompt either (#3905)." }, "triggerPhrases": { "status": "dead",