feat(core): support additive archived task documents (#2375)

## Summary

Re-lands the completed Fusion board task FX-005 on current upstream
`main`, stacked on #2374 (FX-004).

- adds a narrowly authorized additive publication path for archived task
documents
- preserves archived task and mission state and keeps ordinary
replacement/deletion writes rejected
- exposes retained archived current/revision reads
- requires project-scoped revision/hash CAS for publication
- maps malformed, unauthorized, missing, inconsistent, and stale states
safely
- rebases preserved dashboard drafts explicitly after CAS conflicts

## Why

Operators need to append a correction or evidence revision to an
archived task without unarchiving it or weakening ordinary archived-task
immutability.

## Dependency

This branch contains #2374 plus the eight FX-005 commits because
cross-fork PRs cannot target a fork-only base branch. After #2374 lands,
this PR should be rebased or refreshed so its diff collapses to FX-005
only.

## Validation

- PostgreSQL task-store and archived-default suites: 33/33
- dashboard route and editor suites: 321/321
- agent document tools: 22/22
- core, dashboard, and engine typechecks pass

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added optimistic concurrency controls for task document creation and
editing using revisions and content hashes.
* Added safe, authenticated append-only corrections for documents
retained on archived tasks.
* Archived documents and revision history remain available for direct
reading.
* Agent and dashboard tools now report conflicts clearly and support
explicit draft rebasing.
* **Bug Fixes**
  * Prevented stale updates from overwriting newer document content.
* Preserved archived-task immutability while allowing controlled
corrections.
* **Documentation**
* Updated CLI, dashboard, storage, task-management, and agent guidance
for these workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: fusion-merge-train <merge-train@topkoli.local>
Co-authored-by: Fusion <noreply@runfusion.ai>
Co-authored-by: v <v@v.speedport.ip>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
flexi767
2026-07-22 17:30:12 +02:00
committed by GitHub
parent 241a5c94ea
commit f21d3ce132
28 changed files with 1332 additions and 96 deletions

View File

@@ -30,6 +30,55 @@ The published `@runfusion/fusion` CLI bundle also exposes the pi extension tool
Agents should still use `fn_workflow_select` only when the user explicitly requested that workflow or when assigning a workflow to a task they created; they must not reroute arbitrary existing tasks just because another workflow appears more suitable. Prompt-injectable lanes strip workflow approval-bypass flags during `fn_workflow_create` / `fn_workflow_update`; executor-owner paths are the only authoring path that may preserve those flags.
## Runtime task-document publication
`fn_task_document_write` is an agent-extension/runtime tool, not an `fn task` binary subcommand. Task-bound lanes supply `key`, `content`, optional `author`, and optional `expected_revision` / `expected_content_hash`; dashboard chat and planning use the same fields plus required `task_id` for explicit cross-task publication.
For safe publication, first call `fn_task_document_read`, then write with the returned revision and hash:
```json
{
"task_id": "FX-002",
"key": "evidence",
"content": "rebased evidence",
"expected_revision": 3,
"expected_content_hash": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}
```
Revision zero means create only if absent. On success the tool returns the new revision and content hash. A stale expectation returns an error result with code `TASK_DOCUMENT_PRECONDITION_FAILED` and current revision/hash; re-read, reconcile the newer content, and submit a deliberate rebased write. The tool never retries or overwrites automatically. Omitting both expectations retains the legacy unconditional contract. These ordinary tools reject archived parents; there is no `allowArchived` tool parameter.
### Operator API: append to a retained archived document
Archived correction publication is an authenticated HTTP API, not an `fn` binary subcommand or agent tool. It requires active daemon bearer authentication; Fusion launched with `--no-auth` returns `403`. First read the exact current revision/hash, then submit only the suffix:
```bash
BASE=http://127.0.0.1:4040/api
TASK=FX-DISPOSABLE
KEY=docs
TOKEN="$FUSION_DAEMON_TOKEN"
curl -fsS -H "Authorization: Bearer $TOKEN" \
"$BASE/tasks/$TASK/documents/$KEY" > /tmp/fusion-current-document.json
REVISION=$(jq -r .revision /tmp/fusion-current-document.json)
CONTENT_HASH=$(jq -r .contentHash /tmp/fusion-current-document.json)
curl -fsS -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$BASE/tasks/$TASK/documents/$KEY/archived-publications" \
--data "$(jq -n \
--arg appendContent 'Correction text' \
--arg expectedContentHash "$CONTENT_HASH" \
--arg author 'operator' \
--arg reason 'Correct retained evidence' \
--argjson expectedRevision "$REVISION" \
'{appendContent, expectedRevision, expectedContentHash, author, reason}')"
```
Fusion constructs `existing content + "\n\n" + appendContent`; callers cannot send replacement `content` or metadata. Responses are `201` on committed append, `400` for malformed/unknown fields, `403` when the privileged capability is unavailable, `404` for a missing archived parent/document, and `409` for non-archived/inconsistent state or stale CAS. On `409 TASK_DOCUMENT_PRECONDITION_FAILED`, re-read current content/revision/hash, verify whether the correction is still needed, and submit a newly rebased append; never retry the stale body unchanged. In multi-project operation, use the same project selector as other task APIs so every read and publication resolves within one project.
## Workflow commands
```bash