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
72 changes: 72 additions & 0 deletions docs/engineering/jvnautosci_2728_article_checkpoint_incident.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Article checkpoint recovery incident, 7 September 2026

- **Kind:** Incident evidence record
- **Authority:** Observations and causal interpretation; live repair and delivery decision in [JVNAUTOSCI-2728](https://naoinstitute.atlassian.net/browse/JVNAUTOSCI-2728)
- **Request:** `804d2fe7-4148-4859-9c9b-f94f7829a65e`
- **Workflow instance:** `4881438b-3281-4b0f-aeb4-58a1ebb874f5`
- **Original producer:** `e7a0490cf832df19ccf74e0da82bf3f41dd814dc`

## Observed chronology

1. The user requested representation of *An Alien Mind*. The metadata workflow
began at 22:25:59 UTC. An awaited tool call returned a running partial receipt
after its 90-second observation interval; the turn finalised around 22:28:08.
This was an observation expiry, not a transport failure. The model checked
`article_concept_id`, although the workflow contract returns `paper_concept_id`.
2. The article already existed by 22:26:41. Author resolution and canonical
authorship read-back completed by 22:29:19. The saved checkpoint contains
successful article and text-relation reads. The source URL from the original
mail was omitted from the launch inputs and was not stored on the article.
3. At 22:29:42 the complete workflow context was enqueued to the original
checkout's local spillway. Its compressed SHA-256 is
`f4a190ee9a578bc9ed7c2e7ea0acb278b5baaa80473a0980d1f627e8823c1480`.
The checkpoint advanced to `summarise_representation_evidence`.
4. A later restart ran from `Von-runtime-main`. The successor worker claimed the
instance at 22:34:48 and could not find that checkpoint in its own relative
spillway directory. The original bytes remained in `Von/data/blob_spillway`.
5. Execution hydration returned the failed blob reference as if it were usable
workflow context. The summary received no article context, correctly returned
`verification_passed=false`, and the unconditional success transition still
completed the workflow at 22:35:17.

The restart happened after the original partial response. It explains the
subsequent failed recovery, not the original decision to stop observing.

## Causal boundaries

- Local stdio bound operator provenance to selected Gmail/conversation tools,
while telemetry wrappers overwrote provenance with `tool_payload_fallback`.
Thus diagnostics were denied and an existing workflow appeared not found.
- After authority was restored, the original diagnostic and workflow responses
exceeded the stdio response limit. Existing bounded telemetry paging could
serve those records without changing authority or raising the response limit.
- A working-directory-dependent spillway location stranded acknowledged pending
blobs when the runtime moved between linked checkouts.
- Fail-soft loading intended for auxiliary evidence also accepted a missing
top-level execution checkpoint. The saved blob wrapper was truthy, so the
executor resumed the summary state with no domain context.
- The represented summary stage treated successful JSON generation as workflow
success, independently of its own verification result. Its author context also
expected an older aggregate output key instead of the actual author records
and authorship receipts.

## Canonical artefacts and evidence

The article is `#V#external_identity_bibliographic_110c3e4b9ddc8590`. Its authorship
relation targets `#V#external_identity_scholarly_author_occurrence_fe858845354ff098`.
Both were read back through canonical tools before recovery. The source URL was
confirmed from the original Gmail message, with tracking parameters removed:
`https://openai.com/index/an-alien-mind/`.

The original checkpoint and live workflow definition were saved before repair.
Runtime-local blobs were copied to the shared primary spillway with byte/hash
checks, no overwrites, and all originals retained. Raw telemetry and authority
carriers remain in private operational storage, not this repository.

Targeted evidence covers local stdio authority, signed-reference restrictions,
bounded response reconstruction, cross-worktree pending-blob access, missing
essential context, positive/negative summary verification, and article reuse.
The broader workflow-tools suite was interrupted during an external SSL wait;
its partial run is not claimed as a completed validation campaign.

See Jira for live recovery receipts, activation identity and publication status.
13 changes: 12 additions & 1 deletion docs/engineering/operational_engineering_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,18 @@ unchanged verification when needed, and published a current dependency
receipt. This command is not a startup workaround and must not be scheduled on
every restart.

### 3.4 Clean up repeated local helpers
### 3.4 Keep pending blobs accessible across runtime checkouts

The default blob spillway is `data/blob_spillway` in the main Git checkout,
shared by linked worktrees. `VON_BLOB_SPILLWAY_DIR` remains an explicit override;
use an absolute path when multiple processes must share pending blobs. Before
switching an existing deployment from a worktree-local queue, copy its pending
blobs and manifests into the shared directory, check immutable blob hashes,
and preserve the originals until recovery is verified. Missing complete inputs
or workflow checkpoints block execution; diagnostic reads retain the failed
reference so the original bytes can be recovered.

### 3.5 Clean up repeated local helpers

Before starting another server, browser replay, or MCP-heavy batch after
several retries, inspect for:
Expand Down
4 changes: 4 additions & 0 deletions docs/engineering/security_considerations.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ configuration cannot silently reuse the previous account's proxy.
surfaces and may use operator-supplied scope. They are not part of the
ordinary actor-scoped projection and must not be described as though every
MCP route shared its identity model.
- Local stdio diagnostic reads use an explicit server-side operator allow-list
in `mcp_stdio_server.py`. Existing actor contexts are preserved; supplied
telemetry references retain their signed target checks. This does not grant
operator provenance to workflow execution, recovery, or ontology mutation.
- External MCP servers (arXiv, future integrations) may not respect namespace
- No rate limiting on tool invocations
- No audit trail of tool access by user
Expand Down
22 changes: 22 additions & 0 deletions src/backend/integrations/internal_mcp/catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -18530,6 +18530,10 @@ def _turn_execution_namespace_coverage_report(**kwargs):
"created_at",
"identifier_binding",
"history_coverage",
"instance_id",
"workflow_id",
"status",
"current_state",
)


Expand Down Expand Up @@ -18586,6 +18590,20 @@ def _bounded_delegated_telemetry_payload(

if not delegated:
return dict(payload)
return _bounded_telemetry_payload(
payload, arguments=arguments, artifact_kind=artifact_kind,
preserve_inline_below_limit=preserve_inline_below_limit,
)


def _bounded_telemetry_payload(
payload: Mapping[str, Any],
*,
arguments: Mapping[str, Any],
artifact_kind: str,
preserve_inline_below_limit: bool,
) -> dict[str, Any]:
"""Page authorised telemetry independently of its authority carrier."""

import hashlib
import json
Expand Down Expand Up @@ -45733,6 +45751,8 @@ def _build_default_catalogue_task_and_workflow_definitions() -> List[MethodDefin
input_schema=Schema(
required={"instance_id": str},
optional={
"offset": int,
"limit": int,
"await_terminal": (bool, str, int, float),
"advisory_seconds": (int, float),
"timeout_seconds": (int, float),
Expand Down Expand Up @@ -45794,6 +45814,8 @@ def _build_default_catalogue_task_and_workflow_definitions() -> List[MethodDefin
input_schema=Schema(
required={},
optional={
"offset": int,
"limit": int,
"execution_id": (str, type(None)),
"instance_id": (str, type(None)),
},
Expand Down
Loading
Loading