@cassiomc1/forgeloop 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/.github/copilot-instructions.md +1 -0
  2. package/AGENTS.md +1 -0
  3. package/CLAUDE.md +1 -0
  4. package/DOCS_INDEX.md +7 -0
  5. package/EXECUTION_STATE.md +40 -0
  6. package/LOOP_ENGINEERING.md +54 -5
  7. package/LOOP_SYSTEM_DESIGN.md +22 -1
  8. package/PROTOCOL_INTEGRATION.md +41 -0
  9. package/README.md +38 -0
  10. package/TERMINOLOGY.md +15 -0
  11. package/THIRD_PARTY_NOTICES.md +15 -0
  12. package/THREAT_MODEL.md +20 -1
  13. package/docs/ARTIFACT_REFERENCE.md +43 -0
  14. package/docs/CLI_REFERENCE.md +97 -3
  15. package/docs/CROSS_HARNESS_CONTINUITY.md +23 -0
  16. package/docs/DOCUMENTATION_GUIDE.md +14 -0
  17. package/docs/GETTING_STARTED.md +1 -0
  18. package/docs/MCP.md +126 -0
  19. package/docs/RECIPES.md +82 -0
  20. package/docs/RELEASE_CHECKLIST_1_4.md +38 -0
  21. package/docs/RELEASE_CHECKLIST_1_5_MCP.md +78 -0
  22. package/docs/TROUBLESHOOTING.md +111 -1
  23. package/docs/UNIVERSAL_INTEGRATION.md +48 -0
  24. package/package.json +14 -3
  25. package/schemas/task-recovery.schema.json +61 -0
  26. package/src/cli.js +173 -347
  27. package/src/commands/audit.js +5 -0
  28. package/src/commands/inspect.js +6 -0
  29. package/src/commands/progress.js +6 -2
  30. package/src/commands/status.js +17 -0
  31. package/src/commands/task-create.js +39 -1
  32. package/src/commands/task-list.js +14 -1
  33. package/src/commands/task-lock-status.js +2 -2
  34. package/src/commands/task-recover.js +202 -0
  35. package/src/commands/task-repair-legacy-recovery.js +417 -0
  36. package/src/commands/task-resume.js +172 -0
  37. package/src/commands/task-scope.js +23 -4
  38. package/src/commands/task-show.js +18 -4
  39. package/src/commands/validate-protocol.js +19 -2
  40. package/src/core/artifact-registry.js +12 -0
  41. package/src/core/audit.js +20 -4
  42. package/src/core/bundles.js +15 -0
  43. package/src/core/cli-command-definitions.js +50 -4
  44. package/src/core/command-executors.js +387 -0
  45. package/src/core/command-input.js +107 -0
  46. package/src/core/command-runtime.js +106 -0
  47. package/src/core/completion-artifacts.js +2 -3
  48. package/src/core/completion-ownership.js +88 -0
  49. package/src/core/error-codes.js +118 -1
  50. package/src/core/events.js +130 -1
  51. package/src/core/filesystem.js +55 -6
  52. package/src/core/inspect.js +27 -0
  53. package/src/core/integration-invocation-policy.js +170 -0
  54. package/src/core/integration-limits.js +20 -0
  55. package/src/core/integration-resources.js +127 -0
  56. package/src/core/next-action-model.js +60 -0
  57. package/src/core/next-action.js +31 -0
  58. package/src/core/phase.js +2 -1
  59. package/src/core/project-root.js +21 -0
  60. package/src/core/protocol-info.js +13 -0
  61. package/src/core/reconcile-closure.js +32 -10
  62. package/src/core/recovery-history.js +116 -0
  63. package/src/core/schema-validation.js +1 -0
  64. package/src/core/task-claim-state.js +272 -0
  65. package/src/core/task-command.js +5 -1
  66. package/src/core/task-conflict-inspection.js +321 -0
  67. package/src/core/task-context.js +32 -29
  68. package/src/core/task-discovery.js +14 -1
  69. package/src/core/task-lock.js +216 -22
  70. package/src/core/task-paths.js +3 -2
  71. package/src/core/task-recovery-migration.js +192 -0
  72. package/src/core/task-recovery.js +205 -0
  73. package/src/core/task-scope.js +33 -1
  74. package/src/core/templates.js +1 -0
  75. package/src/core/transaction.js +28 -2
  76. package/src/integration.js +47 -0
@@ -8,6 +8,7 @@ Do not treat ForgeLoop as vendor-specific, optional, or to follow only "in spiri
8
8
  Use these instructions across the repository while preserving local rules.
9
9
 
10
10
  - Read [`LOOP_ENGINEERING.md`](../LOOP_ENGINEERING.md) and [`PROTOCOL_INTEGRATION.md`](../PROTOCOL_INTEGRATION.md).
11
+ - If an official ForgeLoop structured integration is available in your host, prefer it for protocol operations; otherwise use the project-local ForgeLoop CLI. Never simulate ForgeLoop-managed lifecycle, claim, recovery, ledger, or completion state directly.
11
12
  - Confirm [`PROJECT_PROFILE.md`](../PROJECT_PROFILE.md) from evidence; initialize if in `template` mode.
12
13
  - Select context with [`GUIDE_ROUTER.md`](../GUIDE_ROUTER.md) and report activated guide IDs.
13
14
  - Respect the latest request, scope, and higher-level instructions.
package/AGENTS.md CHANGED
@@ -7,6 +7,7 @@ Do not treat ForgeLoop as vendor-specific, optional, or to follow only "in spiri
7
7
 
8
8
  1. Follow platform rules, the user's latest request, and local instructions first.
9
9
  1. Read [`LOOP_ENGINEERING.md`](./LOOP_ENGINEERING.md) and [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md).
10
+ 1. If an official ForgeLoop structured integration is available in your host, prefer it for protocol operations; otherwise use the project-local ForgeLoop CLI. Never simulate ForgeLoop-managed lifecycle, claim, recovery, ledger, or completion state directly.
10
11
  1. Inspect [`PROJECT_PROFILE.md`](./PROJECT_PROFILE.md). Confirm facts from sources; initialize if in `template` mode.
11
12
  1. Use [`GUIDE_ROUTER.md`](./GUIDE_ROUTER.md) to select relevant guides and report activated guide IDs.
12
13
  1. Make the smallest coherent change, run specific checks, and proportional regression checks.
package/CLAUDE.md CHANGED
@@ -9,6 +9,7 @@ When working in this repository:
9
9
 
10
10
  1. Follow higher-level instructions, the user's latest request, and local rules first.
11
11
  1. Read [`LOOP_ENGINEERING.md`](./LOOP_ENGINEERING.md) and [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md).
12
+ 1. If an official ForgeLoop structured integration is available in your host, prefer it for protocol operations; otherwise use the project-local ForgeLoop CLI. Never simulate ForgeLoop-managed lifecycle, claim, recovery, ledger, or completion state directly.
12
13
  1. Verify [`PROJECT_PROFILE.md`](./PROJECT_PROFILE.md) against real sources; initialize if in `template` mode.
13
14
  1. Consult [`GUIDE_ROUTER.md`](./GUIDE_ROUTER.md), select relevant guides, and announce their IDs.
14
15
  1. Make small changes, run specific checks, and run proportional regression checks.
package/DOCS_INDEX.md CHANGED
@@ -20,7 +20,11 @@ integration and guide context. Use this map before editing documentation.
20
20
  | Artifact and schema reference | [`docs/ARTIFACT_REFERENCE.md`](./docs/ARTIFACT_REFERENCE.md) | Purpose, mutability, and trust classifications of `.forgeloop/` |
21
21
  | Troubleshooting and recovery | [`docs/TROUBLESHOOTING.md`](./docs/TROUBLESHOOTING.md) | Symptom-first recovery and stable error code reference |
22
22
  | Operational recipes | [`docs/RECIPES.md`](./docs/RECIPES.md) | Short copy-paste recipes for daily workflows |
23
+ | Universal integration API | [`docs/UNIVERSAL_INTEGRATION.md`](./docs/UNIVERSAL_INTEGRATION.md) | Programmatic integration subpath, envelope semantics, and consumer map |
24
+ | Local-first MCP adapter | [`docs/MCP.md`](./docs/MCP.md) | stdio default, optional strict loopback HTTP; server modes/capabilities and canonical resources |
23
25
  | Documentation guide | [`docs/DOCUMENTATION_GUIDE.md`](./docs/DOCUMENTATION_GUIDE.md) | Rules and checklist for modifying documentation |
26
+ | ForgeLoop 1.5/MCP release checklist | [`docs/RELEASE_CHECKLIST_1_5_MCP.md`](./docs/RELEASE_CHECKLIST_1_5_MCP.md) | Integration API v1, MCP package, and publication gates |
27
+ | ForgeLoop 1.4 release checklist | [`docs/RELEASE_CHECKLIST_1_4.md`](./docs/RELEASE_CHECKLIST_1_4.md) | Claim-recovery, compatibility, package, and publication gates |
24
28
  | Lifecycle, gates, planning, verification, and recovery | [`LOOP_ENGINEERING.md`](./LOOP_ENGINEERING.md) | Normative process for agents and developer workflows |
25
29
  | Capability levels, discovery, and degradation | [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md) | Vendor-neutral harness contract |
26
30
  | Host/orchestrator integration | [`ORCHESTRATOR_INTEGRATION.md`](./ORCHESTRATOR_INTEGRATION.md) | Serializable phases, transition boundaries, host responsibilities, and no-runtime integration contract |
@@ -46,6 +50,8 @@ integration and guide context. Use this map before editing documentation.
46
50
  | **Fixing a broken or stale state** | [`docs/TROUBLESHOOTING.md`](./docs/TROUBLESHOOTING.md) |
47
51
  | **Looking for quick recipes** | [`docs/RECIPES.md`](./docs/RECIPES.md) |
48
52
  | **Documentation contributor** | [`docs/DOCUMENTATION_GUIDE.md`](./docs/DOCUMENTATION_GUIDE.md) |
53
+ | **Release maintainer (current)** | [`docs/RELEASE_CHECKLIST_1_5_MCP.md`](./docs/RELEASE_CHECKLIST_1_5_MCP.md) |
54
+ | **Release maintainer (historical 1.4)** | [`docs/RELEASE_CHECKLIST_1_4.md`](./docs/RELEASE_CHECKLIST_1_4.md) |
49
55
  | **Protocol architect / maintainer** | [`LOOP_SYSTEM_DESIGN.md`](./LOOP_SYSTEM_DESIGN.md) + [`schemas/`](./schemas/) |
50
56
  | **Security auditor** | [`THREAT_MODEL.md`](./THREAT_MODEL.md) |
51
57
  | **Engineering guide author** | [`GUIDE_ROUTER.md`](./GUIDE_ROUTER.md) + [`ENG/`](./ENG/) |
@@ -57,6 +63,7 @@ integration and guide context. Use this map before editing documentation.
57
63
  - **Check CLI options and syntax**: [`docs/CLI_REFERENCE.md`](./docs/CLI_REFERENCE.md)
58
64
  - **Understand what `.forgeloop/` stores**: [`docs/ARTIFACT_REFERENCE.md`](./docs/ARTIFACT_REFERENCE.md)
59
65
  - **Fix a blocked, stale, or invalid state**: [`docs/TROUBLESHOOTING.md`](./docs/TROUBLESHOOTING.md)
66
+ - **Recover a stale task or reacquire released claims**: [`docs/RECIPES.md`](./docs/RECIPES.md#recipe-15--release-and-reacquire-claims-for-an-abandoned-task)
60
67
  - **Find operational copy-paste commands**: [`docs/RECIPES.md`](./docs/RECIPES.md)
61
68
  - **Read the normative protocol specification**: [`LOOP_ENGINEERING.md`](./LOOP_ENGINEERING.md)
62
69
  - **Integrate a new AI environment**: [`PROTOCOL_INTEGRATION.md`](./PROTOCOL_INTEGRATION.md)
@@ -10,6 +10,27 @@ Compatible agents may persist a handoff checkpoint at:
10
10
  .forgeloop/task-state/<taskKey>/work-state.json
11
11
  ```
12
12
 
13
+ Claim-release recovery has a separate current-state artifact:
14
+
15
+ ```text
16
+ .forgeloop/task-state/<taskKey>/recovery.json
17
+ ```
18
+
19
+ `work-state.json` remains the lifecycle authority. `recovery.json` records a
20
+ request to suspend ordinary mutation and release effective claims; it does not
21
+ change the phase, refresh repository evidence, erase failures, or imply
22
+ completion. Its `recoveryId`, event sequence, previous revision, released
23
+ claims, repository fingerprint, classification, and authority kind are bound
24
+ to the append-only recovery event. Claims are released only after the canonical
25
+ resolver validates that complete relationship. An unresolved recovery event
26
+ with a missing tombstone, or a tombstone without its matching event, is
27
+ `INCONSISTENT`, retains historical claims, and disables mutation. The same
28
+ fail-closed rule applies to completion: `phase: COMPLETE` alone never releases
29
+ claims — the canonical completion ownership proof (validated ledger with the
30
+ task-bound `COMPLETION_VALIDATED` event and coherent state) is required, and a
31
+ forged or unproven COMPLETE state is `INCONSISTENT` with historical claims
32
+ retained.
33
+
13
34
  The file is local, ignored by Git, schema-versioned, and never a replacement
14
35
  for the manifest or the target project profile (installed as
15
36
  `.forgeloop/kit/PROJECT_PROFILE.md`). It contains no secrets and is untrusted
@@ -66,6 +87,25 @@ Before resuming, compare:
66
87
  - the protocol version;
67
88
  - required artifacts and assumptions recorded by the task.
68
89
 
90
+ If validated recovery state is active, ordinary lifecycle mutation fails with
91
+ `E_TASK_RECOVERED`. If recovery ownership is inconsistent, mutation fails with
92
+ `E_TASK_CLAIM_OWNERSHIP_INCONSISTENT`. Resume claim ownership explicitly:
93
+
94
+ ```bash
95
+ forgeloop task-resume --task <id> --json
96
+ ```
97
+
98
+ Optional repeatable `--claim <path>` arguments replace the historical claim set
99
+ only after normal overlap and clean-checkout enforcement succeeds. Recovery
100
+ state deletion, any descriptor update, and `TASK_RECOVERY_RESUMED` are staged
101
+ transactionally. `TASK_RECOVERY_RESUMED` counts as meaningful activity. A
102
+ missing artifact returns `E_TASK_NOT_RECOVERED` only when the ledger also proves
103
+ there is no unresolved recovery; otherwise it is an ownership inconsistency.
104
+
105
+ Never create, delete, or edit `recovery.json` manually. Never remove recovery
106
+ state to resume a task. Never interpret `recovery.json` without validating its
107
+ ledger binding.
108
+
69
109
  Any material difference produces `REVALIDATION_REQUIRED`. A non-Git target
70
110
  reports that branch/HEAD drift is not verifiable. Cheap checks may be rerun,
71
111
  but a completed destructive or publication action is never rerun automatically.
@@ -1289,7 +1289,7 @@ corruption through three fundamental protocol mechanisms:
1289
1289
  `taskKey` derived as `SHA-256(taskId)` in 64 lowercase hexadecimal characters. All
1290
1290
  task-scoped artifacts (`task.json`, `contract.json`, `routing-result.json`,
1291
1291
  `preflight.json`, `work-state.json`, `events.ndjson`, `execution-receipt.json`,
1292
- `continuity.json`, gates, and execution records) are stored strictly under
1292
+ `continuity.json`, `recovery.json`, gates, and execution records) are stored strictly under
1293
1293
  `.forgeloop/task-state/<taskKey>/`. Shared repository configuration and sources
1294
1294
  (`config.json`, `sources.json`) remain at `.forgeloop/`.
1295
1295
 
@@ -1304,16 +1304,65 @@ corruption through three fundamental protocol mechanisms:
1304
1304
  (`E_TASK_SCOPE_FROZEN`).
1305
1305
  - At verification and completion, Git modifications are validated to ensure no changes
1306
1306
  escaped the task's declared scope (`E_TASK_CHANGE_OUTSIDE_SCOPE`).
1307
+ - `task.json` retains historical claims. Effective claims are empty only after
1308
+ validator-backed `COMPLETE` or when the canonical claim-state resolver
1309
+ validates `recovery.json` against the descriptor, work state, and complete
1310
+ hash-chained recovery history. A tombstone alone never releases claims.
1311
+ - Fake, missing, corrupt, deleted, or mismatched recovery evidence is
1312
+ `INCONSISTENT`: every provable historical claim remains reserved,
1313
+ `mutationAllowed=false`, and overlapping claim acquisition fails with
1314
+ `E_TASK_CLAIM_OWNERSHIP_INCONSISTENT`.
1315
+ - Recovery is not completion. `task-recover` accepts only deterministic
1316
+ `STALE` or `ABANDONED` classifications, preserves work state, receipts,
1317
+ failures, policy, continuity, and repository fingerprints, and suspends
1318
+ ordinary task mutation with `E_TASK_RECOVERED`.
1319
+ - Only `forgeloop task-resume --task <id>` may remove recovery state. It
1320
+ first validates recovery ownership and lifecycle revision, safely settles
1321
+ only an unchanged stale task lease, then reacquires the released (or
1322
+ explicitly supplied) claims through the normal overlap and clean-checkout
1323
+ checks under the project claims lock. A claim held by another task remains
1324
+ unavailable. `TASK_RECOVERY_RESUMED` is meaningful activity.
1307
1325
 
1308
1326
  3. **Per-Task Exclusive Mutex Locking**:
1309
1327
  Mutating lifecycle commands (`advance`, `preflight`, `run-check`, `complete`, etc.)
1310
- acquire an exclusive filesystem lock at `.forgeloop/task-state/<taskKey>/.lock` using
1328
+ acquire an exclusive filesystem lock at `.forgeloop/locks/<taskKey>.lock` using
1311
1329
  atomic creation flags (`wx`). Concurrent mutations on the same task reject with
1312
1330
  `E_TASK_LOCKED`. Read-only commands (`status`, `audit`, `inspect`, `continuity`) bypass
1313
- locking. Stale locks can be cleared with `forgeloop task-unlock --task <id> --force`.
1331
+ locking. Lock inspection distinguishes `NONE`, `LIVE`, `STALE`, `UNKNOWN`,
1332
+ and `CORRUPT`; unknown or corrupt ownership fails closed. Stale-only release
1333
+ compares the observed lock ID, heartbeat, and owner instance before deletion.
1334
+
1335
+ Recovery that changes claim ownership acquires the project claims lock before
1336
+ the task lock, safely settles an unchanged stale lease, then revalidates phase,
1337
+ work-state revision, ledger sequence, and the `STALE`/`ABANDONED` allowlist
1338
+ before committing `recovery.json` and its append-only event in one transaction.
1339
+ The project claims lock itself uses the same `NONE`/`LIVE`/`STALE`/`UNKNOWN`/
1340
+ `CORRUPT` lease classification and CAS-safe quarantine/restore semantics;
1341
+ unknown, corrupt, or concurrently replaced ownership fails with
1342
+ `E_PROJECT_CLAIMS_LOCK_INCONSISTENT`.
1343
+ The standalone acknowledgement flag does not grant host authority:
1344
+
1345
+ ```text
1346
+ --acknowledge-recovery
1347
+
1348
+ HOST_ATTESTED
1349
+ ```
1350
+
1351
+ `forgeloop next --task <id> --json` maps conflict evidence to structured
1352
+ `RECONCILE_CLOSURE`, `RECOVER_TASK`, `RESUME_RECOVERED_TASK`, or
1353
+ `RESOLVE_RECOVERY_INCONSISTENCY` guidance. A `RECOVERABLE` task must use its
1354
+ canonical reconciliation path and cannot release claims through `task-recover`.
1314
1355
 
1315
1356
  4. **Task Resolution & Legacy Migration**:
1316
1357
  Commands select their target task via `--task <id>`, the `FORGELOOP_TASK` environment
1317
- variable, or implicit single-task fallback. If multiple active tasks exist without a
1318
- selector, ForgeLoop fails closed with `E_TASK_AMBIGUOUS`. Legacy ForgeLoop 1.0 single-task
1358
+ variable, or implicit single-task fallback. Only mutation-active tasks are
1359
+ implicit candidates; recovered, inconsistent, and `COMPLETE` tasks remain
1360
+ explicitly addressable but do not make unrelated work ambiguous. If multiple
1361
+ mutation-active tasks exist without a selector, ForgeLoop fails closed with
1362
+ `E_TASK_AMBIGUOUS`. Legacy ForgeLoop 1.0 single-task
1319
1363
  layouts can be migrated into namespaced layout using `forgeloop task-migrate`.
1364
+
1365
+ A project containing active task recovery state requires ForgeLoop 1.4.0 or
1366
+ newer.
1367
+ <a id="FL-CLAIM-002"></a> **FL-CLAIM-002 — Harnesses that cannot validate task-recovery schema v1 and its linked ledger history MUST refuse**
1368
+ ownership mutation rather than fall back to descriptor-only claims.
@@ -380,12 +380,33 @@ registry. If it is not available yet, the same commands can run as
380
380
  documents into `.forgeloop/kit/`, keeps only native instruction shims at the
381
381
  target root, and leaves project-scoped configuration under `.forgeloop/` while
382
382
  isolating modern mutable task protocol state (contract, route, gate, state,
383
- event, preflight, and receipt artifacts) under
383
+ event, preflight, receipt, and recovery artifacts) under
384
384
  `.forgeloop/task-state/<taskKey>/`. Legacy singleton artifacts remain under
385
385
  `.forgeloop/` for compatibility and migration only. Manual copying must
386
386
  preserve that target layout; copying package-source root files directly is not
387
387
  equivalent to `forgeloop init`.
388
388
 
389
+ Recovery uses a relational state model: `work-state.json` owns the lifecycle
390
+ phase, `task.json` retains historical claims, `recovery.json` records current
391
+ suspension, and the complete hash-chained ledger proves recovery/resume cycles.
392
+ Only their canonical validated projection can release effective claims. The
393
+ same holds for completion: `RELEASED_BY_COMPLETION` requires the canonical
394
+ completion ownership proof (COMPLETE phase plus a validated ledger containing
395
+ the task-bound `COMPLETION_VALIDATED` event with coherent state and no
396
+ contradicting later lifecycle event); a manually forged COMPLETE state is
397
+ `INCONSISTENT`, retains historical claims, and disables mutation. Any
398
+ missing, corrupt, forged, or mismatched relationship is `INCONSISTENT`, retains
399
+ historical claims, and disables mutation. Recovery never fabricates completion;
400
+ `task-resume` is the only path that rechecks and reacquires ownership before
401
+ removing the recovery artifact. Project claim serialization always precedes
402
+ the per-task lock for create, scope, recover, and resume operations, and both
403
+ lock classes use lease classification plus CAS-safe stale settlement. Task
404
+ locks additionally require complete owner identity (`taskId`, `lockId`,
405
+ `ownerInstanceId`, `operation`, heartbeat, positive lease): incomplete identity
406
+ classifies `UNKNOWN` and is never eligible for stale release. Implicit task
407
+ selection distinguishes read-only discoverability (`READ`: any single healthy
408
+ task) from mutation authority (`MUTATION`: only operationally active tasks).
409
+
389
410
  The README explains the file set, activation behavior, current/relative/absolute
390
411
  target installation, first-run profile flow, local validation commands, and safe
391
412
  update practice.
@@ -158,6 +158,7 @@ The following protocol artifacts are strictly owned by ForgeLoop:
158
158
  - `.forgeloop/task-state/<taskKey>/work-state.json`
159
159
  - `.forgeloop/task-state/<taskKey>/events.ndjson`
160
160
  - `.forgeloop/task-state/<taskKey>/execution-receipt.json`
161
+ - `.forgeloop/task-state/<taskKey>/recovery.json`
161
162
  - `.forgeloop/task-state/<taskKey>/executions/<executionId>.json`
162
163
  - Canonical check, evidence, and terminal-result state
163
164
 
@@ -231,6 +232,21 @@ actor claim ≠ operator grant
231
232
  Authority cannot be self-issued by the actor consuming it. Boolean fields inside
232
233
  verification evidence are not sufficient proof of installation authority.
233
234
 
235
+ The same rule applies to claim-release recovery. The standalone
236
+ `--acknowledge-recovery` flag records `CALLER_ACKNOWLEDGED`; it is an explicit
237
+ request, not a host grant. The deprecated `--operator-authorized` spelling is
238
+ only a compatibility alias and has identical caller-acknowledgement semantics.
239
+ `HOST_ATTESTED` recovery metadata is valid only when a host integration supplies
240
+ a trusted grant reference through a boundary the active actor cannot mint or
241
+ replace. The standalone CLI does not expose such a self-attestation option.
242
+
243
+ Claim ownership is a validated relationship, not an artifact preference.
244
+ <a id="FL-CLAIM-001"></a> **FL-CLAIM-001 — Every harness MUST consume the canonical claim-state resolver**
245
+ over the descriptor, work state, recovery artifact, and complete validated
246
+ recovery history. The resolver retains historical claims and disables mutation
247
+ when that relationship is `INCONSISTENT`; reading `recovery.json` alone is
248
+ non-conforming.
249
+
234
250
  ### Authority provenance
235
251
 
236
252
  Authority provenance is external to actor-authored project state. An external
@@ -354,4 +370,29 @@ ForgeLoop integrates executable verification rules directly into the lifecycle:
354
370
  - **Autonomy Principle**: Non-interactive execution is preserved. Tools, commands, and validators operate unattended with standard input closed and without interactive prompt dependencies.
355
371
  - **Baseline Protection**: Re-recording baseline debt mid-task is rejected with `E_BASELINE_RECORD_DURING_ACTIVE_TASK`; only monotonic ratchet-down is allowed during active tasks (`baseline --update`). Explicit re-recording requires `--policy-reset-authorized`.
356
372
  - **Semantic Recovery**: `forgeloop next` maps policy findings directly to actionable recovery actions (`RESTORE_POLICY`, `REPAIR_CHECKER`, `REPAIR_POLICY`, `REVERIFY_AFTER_POLICY_CHANGE`, `RESTORE_BASELINE`, `CONTINUE_WITH_EXISTING_BASELINE`, `RESOLVE_INERT_CHECK`).
373
+ - **Claim Recovery**: `forgeloop next` maps validated task ownership to `RECONCILE_CLOSURE`, `RECOVER_TASK`, `RESUME_RECOVERED_TASK`, or `RESOLVE_RECOVERY_INCONSISTENCY`. `task-recover` is restricted to `STALE`/`ABANDONED`; it writes durable `recovery.json` plus an append-only event without changing lifecycle evidence. `task-resume` validates the same ownership projection, safely settles an unchanged stale task lock, reuses canonical scope conflict checks, and removes recovery state transactionally.
357
374
  - **Task Scoping**: Task-specific policy snapshots and state live under `.forgeloop/task-state/<taskKey>/` to ensure clean multi-task isolation and cross-harness continuity.
375
+
376
+ ## Structured integration surfaces
377
+
378
+ When a host provides an official ForgeLoop structured integration, prefer it
379
+ for protocol operations; otherwise use the project-local ForgeLoop CLI. Both
380
+ surfaces execute the same canonical commands and share one protocol authority:
381
+ `.forgeloop/` state written only by ForgeLoop itself.
382
+
383
+ - `@cassiomc1/forgeloop/integration` (integration API version 1): the
384
+ transport-neutral programmatic runtime. Domain rejections keep `ok:true`
385
+ with a non-zero exit code; public error codes are preserved verbatim.
386
+ - `@cassiomc1/forgeloop-mcp` (local stdio MCP): an adapter over the same API.
387
+ It never edits `.forgeloop/` state directly, never synthesizes authority,
388
+ and never derives claim ownership outside the canonical resolver
389
+ (`features.integrationApi.version >= 1` in `protocol-info --json`).
390
+
391
+ ForgeLoop applicability never depends on MCP availability: instruction-only
392
+ hosts remain fully supported through the CLI and instruction adapters.
393
+
394
+ `protocol-info --json` advertises claim-recovery capability version 1 under
395
+ `features.taskClaimRecovery`. A project containing active task recovery state
396
+ requires ForgeLoop 1.4.0 or newer.
397
+ <a id="FL-CLAIM-003"></a> **FL-CLAIM-003 — A reader without `validatedClaimProjection=true` MUST fail closed**
398
+ and must not mutate claims.
package/README.md CHANGED
@@ -195,6 +195,15 @@ forgeloop task-create --task auth-feature --claim src/auth --claim tests/auth --
195
195
  # List active and completed tasks
196
196
  forgeloop task-list --json
197
197
 
198
+ # Ask for deterministic conflict/recovery guidance
199
+ forgeloop next --task auth-feature --json
200
+
201
+ # Only for a task classified STALE or ABANDONED: release effective claims
202
+ forgeloop task-recover --task auth-feature --acknowledge-recovery --json
203
+
204
+ # Reacquire conflict-free claims before mutating a recovered task again
205
+ forgeloop task-resume --task auth-feature --json
206
+
198
207
  # Run standard lifecycle commands targeting the task
199
208
  forgeloop route --task auth-feature --work clean-code --surface backend
200
209
  forgeloop preflight --task auth-feature --json
@@ -205,6 +214,16 @@ forgeloop complete --task auth-feature --json
205
214
  forgeloop task-migrate --json
206
215
  ```
207
216
 
217
+ Recovery is not completion. Effective claims become empty only when the
218
+ canonical claim-state resolver validates the relationship between `task.json`,
219
+ `work-state.json`, `recovery.json`, and the complete hash-chained recovery
220
+ history. Fake, missing, corrupt, deleted, or mismatched recovery evidence is
221
+ `INCONSISTENT`: historical claims remain reserved and mutation remains
222
+ disabled. The standalone acknowledgement flag is not host-attested authority.
223
+ `task-resume` removes recovery state only after validated ownership, stale-lock
224
+ settlement, normal claim-overlap, and clean-checkout checks succeed. Never
225
+ create, edit, or delete `recovery.json` manually.
226
+
208
227
  ### Executable policy verification & brownfield baselines
209
228
 
210
229
  ForgeLoop enforces automated, non-interactive verification rules (`rules.json`) with zero interactive dependencies:
@@ -272,6 +291,11 @@ Consumers must reject unknown artifact fields rather than silently treating
272
291
  unrecognized protocol data as valid. The compatibility marker is
273
292
  [`tests/fixtures/compatibility/protocol-v1.json`](./tests/fixtures/compatibility/protocol-v1.json).
274
293
 
294
+ A project containing active task recovery state requires ForgeLoop 1.4.0 or
295
+ newer. A reader that does not advertise
296
+ `features.taskClaimRecovery.validatedClaimProjection=true` must fail closed;
297
+ it must not infer current ownership from `task.json` or `recovery.json` alone.
298
+
275
299
  ## Security and dependency boundary
276
300
 
277
301
  The runtime uses Node built-ins only and does not install agents, providers,
@@ -378,3 +402,17 @@ Task-scoped mutable protocol state is stored under
378
402
 
379
403
  For document ownership, guide routing, capability degradation, and integration
380
404
  details, start at [`DOCS_INDEX.md`](./DOCS_INDEX.md).
405
+
406
+ ## Programmatic integration and MCP
407
+
408
+ ForgeLoop exposes a stable programmatic surface:
409
+
410
+ ```js
411
+ import { executeForgeLoopCommand } from "@cassiomc1/forgeloop/integration";
412
+ ```
413
+
414
+ The local MCP server (`@cassiomc1/forgeloop-mcp`, stdio) is an adapter over
415
+ this exact API — it never reimplements ForgeLoop. See
416
+ [`docs/UNIVERSAL_INTEGRATION.md`](./docs/UNIVERSAL_INTEGRATION.md) and
417
+ [`docs/MCP.md`](./docs/MCP.md). MCP is optional; the CLI and instruction-only
418
+ hosts remain fully supported without it.
package/TERMINOLOGY.md CHANGED
@@ -18,9 +18,24 @@
18
18
  | Runtime | A process that owns execution, scheduling, model calls, or persistence; `ForgeLoop` intentionally does not provide one. |
19
19
  | Evidence kind | One of `OBSERVED`, `INFERRED`, `NOT_VERIFIED`, or `BLOCKED`; evidence never upgrades an unverified claim by itself. |
20
20
  | Required artifact | A checkpoint-recorded relative path and SHA-256 hash that must still match before resume. |
21
+ | Integration API | The stable programmatic surface (`@cassiomc1/forgeloop/integration`) used by structured consumers instead of parsing CLI output. |
22
+ | MCP adapter | The local-first Model Context Protocol server package; an adapter over canonical ForgeLoop commands, never a second implementation. |
23
+ | Server mode | The MCP launch policy tier (`readonly`, `safe`, `full`) that determines which tool classes are available. |
24
+ | Launch capability | A process-scoped, immutable MCP flag (`--allow-*`) required by higher-risk invocation classes; tool input cannot grant it. |
25
+ | Claim state | Canonical ownership classification (`ACTIVE`, `RELEASED_BY_COMPLETION`, `RELEASED_BY_RECOVERY`, `INCONSISTENT`) produced only by the validated claim resolver. |
26
+ | Historical write claims | Claims recorded as evidence in the task descriptor/recovery history after validated release. |
27
+ | Effective write claims | The claims currently enforced against overlapping acquisition; empty only for validated completion or recovery. |
28
+ | Completion ownership proof | The validated lifecycle/ledger evidence (canonical `COMPLETION_VALIDATED` + coherence) required before COMPLETE releases claims. |
29
+ | Caller acknowledgement | Explicit current-caller authorization for recovery actions; never equivalent to host attestation. |
30
+ | Legacy recovery migration | The narrow append-only repair that materializes one recognized historical recovery boundary into the modern durable representation. |
21
31
  | Conformance | Relationship validation across route, state, receipt, task brief, and delegated-result artifacts. |
22
32
  | Universal applicability | ForgeLoop applies whenever an execution environment discovers a project adapter, regardless of model, provider, agent, IDE, or tool name. |
23
33
  | Integration level | The capability tier of an execution environment (`INSTRUCTION_DISCOVERED`, `PROTOCOL_CAPABLE`, `PROTOCOL_LIMITED`, `CONFORMANCE_VERIFIED`). |
34
+ | Recovered task | A non-terminal task whose ordinary mutation authority is suspended and whose effective write claims are released by durable `recovery.json` state. |
35
+ | Recovery acknowledgement | A caller declaration that it intends to recover a task classified `STALE` or `ABANDONED`; it is not a host-attested authority grant. |
36
+ | Historical claims | The write claims retained in `task.json` as task history, including while recovery releases their active ownership. |
37
+ | Effective claims | The claims currently enforced for ownership conflicts: descriptor claims for an active task, or an empty set after validator-backed completion or active recovery. |
38
+ | Claim reacquisition | The serialized `task-resume` operation that rechecks conflicts and checkout cleanliness before removing recovery state and restoring mutation authority. |
24
39
 
25
40
  | Execution continuity | Bounded current-task implementation context used to resume the same ForgeLoop task across sessions or harnesses. |
26
41
  | Continuity artifact | `.forgeloop/continuity.json`; non-evidence operational context bound to canonical work state. |
@@ -195,3 +195,18 @@ The contextual frontend taste guide is informed by Taste Skill:
195
195
  ForgeLoop includes a short, adapted guide under `ENG/taste-frontend-eng.md`.
196
196
  It does not vendor upstream runtime code, depend on its repository at runtime,
197
197
  or make its prescriptive examples universal.
198
+
199
+ ## Runtime dependencies with upstream notices
200
+
201
+ ### Model Context Protocol SDK (MCP package only)
202
+
203
+ - Packages: `@modelcontextprotocol/server` and `@modelcontextprotocol/client`
204
+ (test/smoke only), used by `integrations/mcp`. Published from the canonical
205
+ upstream repository:
206
+ [modelcontextprotocol/typescript-sdk](https://github.com/modelcontextprotocol/typescript-sdk).
207
+ - License declared by the upstream project: MIT.
208
+ - Use in this collection: official SDK transport/server primitives for the
209
+ local stdio ForgeLoop MCP adapter.
210
+ - Boundary: the ForgeLoop core package (`@cassiomc1/forgeloop`) has no
211
+ dependency on the MCP SDK; the SDK ships only inside
212
+ `@cassiomc1/forgeloop-mcp`. Review upstream terms before redistribution.
package/THREAT_MODEL.md CHANGED
@@ -18,7 +18,26 @@ remaining trust boundaries and their executable evidence.
18
18
  | Forged preparation | Makes an agent's prose claim look like a completed preflight | Contract, route, gate, and preflight artifacts | Canonical SHA-256 fingerprints, guide-declared gate requirements, stale-artifact checks, and `E_*` failures | The CLI cannot stop a separate process from writing project files before preflight | `tests/protocol-artifacts.test.js`, `tests/preflight.test.js` |
19
19
  | Chronology rewrite | Hides execution before route, gates, or verification | `.forgeloop/events.ndjson` | Append-only local ledger, sequence numbers, hash chaining, and chronology validation without prompts or hidden reasoning | A privileged process can still replace the ledger after validation | `tests/lifecycle.test.js` |
20
20
  | Concurrent protocol mutation | Two writers read the same state or ledger tail and silently overwrite each other | Task state, task event ledger, and transaction journal | Mutations acquire a lease-bearing task lock, stage writes in `.forgeloop/.txn/`, preserve a recovery manifest, and publish only after the callback completes; state mutators use an expected revision, while ledger appends validate a tail checkpoint and stage only a synchronized suffix | The filesystem does not provide a multi-file atomic commit primitive; a process killed during append is recovered by truncating to the journaled pre-append size rather than treated as complete | `tests/state-revision.test.js`, `tests/concurrent-ledger.test.js`, `tests/scale-ledger.test.js`, `tests/transaction.test.js` |
21
- | Stale lock theft | A live process loses exclusive ownership because another process removes its lock | `.forgeloop/locks/<taskKey>.lock` | Locks record hostname, owner instance ID, heartbeat, and lease; inspection classifies `LIVE`, `STALE`, or `UNKNOWN`; ordinary recovery releases only an expired lease and `--force` is explicit | A malicious or separately privileged actor can still delete local locks | `tests/task-cli.test.js`, `tests/task-foundation.test.js` |
21
+ | Stale lock theft | A live process loses exclusive ownership because another process removes or replaces its lock | `.forgeloop/locks/<taskKey>.lock` | Locks record hostname, owner instance ID, heartbeat, and lease; inspection distinguishes `NONE`, `LIVE`, `STALE`, `UNKNOWN`, and `CORRUPT`; stale-only release quarantines the observed inode and compares lock ID, heartbeat, and owner instance before deletion | A malicious or separately privileged actor can still delete local locks; an expired lease remains a recovery heuristic rather than remote liveness proof | `tests/task-lock.test.js`, `tests/task-recover.test.js` |
22
+ | Forged recovery tombstone | A schema-valid fake `recovery.json` makes historical claims disappear without an official recovery event | Task descriptor, recovery artifact, and complete event ledger | The canonical claim-state resolver releases claims only when every artifact field matches one unresolved recovery history cycle; a tombstone alone is `INCONSISTENT`, retains historical claims, and disables mutation | A privileged actor can replace every linked local artifact; validation proves consistency, not remote attestation | `tests/task-claim-state.test.js`, `tests/task-claim-ownership-integration.test.js`, `tests/task-recovery-invariants.test.js` |
23
+ | Forged completion claim release | An actor changes `work-state.phase` to `COMPLETE` to make write claims disappear without canonical completion | Work state, canonical completion event, and the complete validated event ledger | Claim ownership releases COMPLETE claims only when state and a validated lifecycle ledger prove canonical completion (`COMPLETION_VALIDATED` bound to the task, coherent state/ledger, no contradicting later lifecycle event); otherwise ownership is `INCONSISTENT` with historical claims retained, mutation disabled, and overlapping acquisition blocked (`E_COMPLETION_OWNERSHIP_UNPROVEN`) | A separately privileged actor can rewrite all local artifacts consistently; ForgeLoop provides consistency verification, not external cryptographic attestation | `tests/completion-claim-ownership.test.js`, `tests/task-claim-state.test.js` |
24
+ | Incomplete task-lock identity theft | A structurally incomplete persisted task lock (missing lockId, owner instance, operation, or lease) with plausible timestamps is classified LIVE/STALE and removed as stale | `.forgeloop/locks/<taskKey>.lock` identity validation | Task lock identity requires `taskId`, `lockId`, `ownerInstanceId`, `operation`, heartbeat, and a positive integer lease; incomplete metadata classifies `UNKNOWN` (never stale-releasable), lease values are never defaulted at validation time, and CAS release additionally requires `lock.taskId === requested taskId` plus unchanged observed identity | A privileged writer can still forge a fully identified lock; classification proves structure, not liveness | `tests/task-lock.test.js` |
25
+ | Partial already-repaired relationship | A tampered recovery artifact (claims, classification, revision, fingerprint, or authority edited after migration) is accepted as an idempotent already-repaired no-op | Full canonical relationship validation in `alreadyRepaired` | Idempotency requires the complete validated ownership projection (`RELEASED_BY_RECOVERY` with matching recovery id/seq) and every artifact field agreeing with the canonical migration event; any mismatch fails closed | A separately privileged actor can rewrite all local artifacts consistently; validation proves consistency, not attestation | `tests/task-repair-legacy-recovery.test.js` |
26
+ | Forged legacy-migration authority | A forged `LEGACY_RECOVERY_MIGRATION_RECORDED` claims `HOST_ATTESTED` authority to impersonate a host grant | Migration event authority validation | Legacy migration v1 accepts only `CALLER_ACKNOWLEDGED`; any other authority kind makes the event invalid and the ledger INCONSISTENT | Normal recovery events retain their own host-attestation boundary with trusted grant references | `tests/task-repair-legacy-recovery.test.js` |
27
+ | MCP project-root substitution | A tool call supplies a different project root to read or mutate an unintended target | Immutable server-pinned project context | The ForgeLoop MCP server realpaths the project root once at startup and freezes it; project root is never a tool input | A privileged local process can still target other roots by launching its own server | `integrations/mcp/tests/` |
28
+ | MCP claim-projection fork | An adapter derives claim ownership from raw artifacts (task.json, recovery.json) and disagrees with the canonical resolver | Canonical ownership resource | The `task/ownership` resource is derived exclusively from `resolveTaskClaimState()`; forged COMPLETE stays INCONSISTENT with retained claims through the resource surface | Presentation bugs could still mislabel values; the resolver remains the single authority | `integrations/mcp/tests/ownership.test.js`, `tests/integration-resources.test.js` |
29
+ | MCP capability escalation via tool input | Tool input (e.g. `force: true`, `acknowledgeRecovery: true`) elevates a server started without the matching capability | Launch-level capability gates re-checked per invocation | Risk classification is invocation-level; disabled capabilities refuse with `E_MCP_CAPABILITY_DISABLED`; recovery acknowledgement never upgrades launch policy; legacy repair stays hidden by default; deprecated `operatorAuthorized` is absent from schemas | A separately authorized local actor can restart the server in full mode | `integrations/mcp/tests/policy.test.js`, `integrations/mcp/tests/safety.test.js` |
30
+ | MCP HTTP unauthenticated remote bind | A network-bound MCP endpoint exposes ForgeLoop operations to any reachable client without authentication | Loopback-only bind policy | The HTTP transport refuses every non-loopback bind with `E_MCP_REMOTE_NOT_SUPPORTED`; Host/Origin validation is defense against DNS rebinding, not authentication; remote access stays disabled until a separately designed authenticated boundary exists | A same-host process can still reach the loopback endpoint | `integrations/mcp/tests/http.test.js` |
31
+ | MCP protocol downgrade / legacy fallback | Legacy-era traffic is silently served, weakening the declared 2026 security posture | Strict modern mode | The HTTP handler is constructed with the SDK strict-modern setting (`legacy: "reject"`); legacy handshakes are answered with an unsupported-protocol-version rejection instead of being served | Stdio remains available for clients that only speak older protocol generations | `integrations/mcp/tests/http.test.js` |
32
+ | MCP HTTP resource exhaustion | Slow headers, slow bodies, oversized bodies, or connection floods exhaust server resources | Bounded transport controls | Header/request/keepalive timeouts are set on the HTTP server; request bodies are hard-bounded at 4 MiB (413 on exceed); an in-flight ceiling sheds load with 503 `E_MCP_HTTP_BUSY`; only POST is served | Bounds protect availability, not authorization | `integrations/mcp/tests/http.test.js` |
33
+ | Transport metadata as authority | An MCP session id, HTTP source address, Origin/Host header, or tool-supplied acknowledgement is treated as ForgeLoop authority | Authority-free adapter design | No session identity is issued or consumed; capability policy is fixed at launch and re-checked per invocation; acknowledgement fields satisfy canonical command semantics only after launch-level capability was granted | None within the adapter boundary; host-level network controls remain external | `integrations/mcp/tests/policy.test.js` |
34
+ | MCP stdout corruption / shell injection | Protocol transport polluted by diagnostics, or a generic shell tool enabling arbitrary execution | Transport discipline and exact-argv policy | stdout carries only MCP protocol; logging goes to stderr; no shell/exec tools exist; external execution passes exact argv arrays through canonical provenance | Compromised dependencies remain out of scope of transport discipline | `scripts/mcp-package-smoke.mjs` |
35
+ | Recovery tombstone deletion / claim resurrection | Deleting `recovery.json` lets a recovered task mutate after another task adopts the released scope | Recovery history and all ordinary task mutation entry points | The complete ledger derives unresolved recovery independently; a missing tombstone with unresolved history is `INCONSISTENT`, and the canonical mutation guard rejects it with `E_TASK_CLAIM_OWNERSHIP_INCONSISTENT` | A separately privileged process can still deny service by corrupting local artifacts | `tests/task-claim-state.test.js`, `tests/task-claim-ownership-integration.test.js` |
36
+ | Corrupt task namespace claim disappearance | An unreadable descriptor or recovery artifact is interpreted as claim-free during task creation or scope change | Modern task namespace discovery and project claim acquisition | Readable historical claims are retained conservatively; an unhealthy namespace with unknown ownership blocks claim mutation globally with `E_TASK_CLAIM_OWNERSHIP_INCONSISTENT` | Recovery requires repairing protocol-owned evidence; ForgeLoop does not invent unknown claims | `tests/task-claim-ownership-integration.test.js`, `tests/task-recovery-tamper.test.js` |
37
+ | Recovery event-tail eviction | Later ledger events push recovery history beyond a bounded read window and reactivate old claims | Recovery state versus append-only event history | Claim ownership validates the complete ledger and binds the artifact to its exact recovery event, recovery ID, claims, classification, authority, revision, and repository fingerprint | Full validation is intentionally correctness-first and may be optimized only with verdict-equivalent checkpoints | `tests/task-recover.test.js`, `tests/task-recovery-validation.test.js`, `tests/task-recovery-invariants.test.js` |
38
+ | Project claims lock deadlock or theft | A crashed process blocks every ownership transition, or stale cleanup removes a replacement owner | `.forgeloop/.claims.lock` | Project claim locks classify `NONE`, `LIVE`, `STALE`, `UNKNOWN`, and `CORRUPT`; acquisition may quarantine and remove only an unchanged stale inode after matching lock ID, heartbeat, and owner instance, while unknown/corrupt/CAS-mismatch state fails closed | Lease expiry is a recovery heuristic; separately privileged filesystem writers remain outside the boundary | `tests/project-claims-lock.test.js`, `tests/task-recovery-concurrency.test.js` |
39
+ | Self-asserted recovery authority | An actor labels its own recovery request operator- or host-authorized | Caller input, recovery authority metadata, and host integration boundary | Standalone recovery records only `CALLER_ACKNOWLEDGED`; the deprecated operator flag is only an alias; `HOST_ATTESTED` requires a host-owned grant reference and cannot be minted by the CLI | Host attestation remains only as strong as the host-controlled boundary and grant source | `tests/task-recovery-cli.test.js`, `tests/task-recovery-validation.test.js` |
40
+ | Recovery TOCTOU and reacquisition collision | State changes between inspection and claim release, or two tasks acquire the same released path | Project claims lock, task lock, revision, ledger sequence, and scope checks | Project-claims lock precedes task lock; recovery revalidates validated ownership, classification, revision, phase, and ledger sequence; resume validates the same ownership, CAS-settles stale task locks, and reuses normal conflict and clean-scope enforcement; concurrent tests assert at most one active owner | The filesystem cannot make repository content and multi-file metadata globally atomic against separately privileged writers | `tests/task-recovery-concurrency.test.js`, `tests/project-claims-lock.test.js`, `tests/task-lock.test.js`, `tests/task-resume.test.js` |
22
41
  | Lifecycle artifact repair | Direct state or receipt edits fabricate a legal recovery or terminal phase | Work state, receipt, evidence checks, and event ledger | New verification cycles record phase events and fingerprints; validators reject state/ledger divergence and future lifecycle evidence | Local artifacts are detection-oriented, not cryptographically tamper-proof against a privileged process rewriting every linked artifact | `tests/lifecycle-evidence-recovery.test.js`, `tests/completion-ergonomics.test.js` |
23
42
  | Unsupported profile fact | Turns an agent decision into a durable user fact | `PROJECT_PROFILE.md` and `.forgeloop/sources.json` | Source IDs, source-kind validation, unknown-reference rejection, and explicit misclassification failures | Arbitrary Markdown semantics still require a human or host-specific parser | `tests/profile-provenance.test.js`, `src/core/profile.js` |
24
43
  | Weak verification | Treats a vague or inferred claim as observed evidence | Receipt checks and coverage | Versioned check schema, contradictory-status rejection, observed-evidence requirements, and coverage matrix | Evidence remains local and declarative; it is not a remote attestation service | `tests/evidence-coverage.test.js`, `tests/completion.test.js` |
@@ -30,6 +30,7 @@ All artifact schemas are defined in `schemas/*.schema.json`. Persisted artifact
30
30
  | `policy/baseline.json` | `policy-baseline` | Protocol Generated Or Operator | Monotonic Ratchet Down | Brownfield Baseline |
31
31
  | `policy/policy.lock` | `policy-lock` | Protocol Generated | Atomic Digest Compilation | Policy Integrity Lock |
32
32
  | `task-state/<task-key>/policy-snapshot.json` | `policy-snapshot` | Protocol Generated | Mutable Before Execution | Task Policy Attestation |
33
+ | `task-state/<task-key>/recovery.json` | `task-recovery` | Protocol Generated | Recovery State Transitions | Task Recovery State |
33
34
 
34
35
  <!-- END FORGELOOP GENERATED: artifact-registry -->
35
36
 
@@ -601,3 +602,45 @@ comparison explicitly `UNKNOWN` rather than assuming an empty baseline.
601
602
  - `capturedAt` *(string, optional)*
602
603
 
603
604
  <!-- END FORGELOOP GENERATED: schema:policy-snapshot -->
605
+
606
+ ---
607
+
608
+ ### 2.19 `task-state/<taskKey>/recovery.json`
609
+
610
+ <!-- forgeloop-doc: schema=task-recovery artifact=.forgeloop/task-state/<task-key>/recovery.json -->
611
+
612
+ Durable current-state input for claim-release recovery. It records the
613
+ classification and exact claims released while leaving lifecycle work state,
614
+ receipts, failures, policy, and continuity unchanged. Structural validity alone
615
+ does not release claims: ForgeLoop must also validate the descriptor, work
616
+ state, full ledger, referenced recovery event, and absence of a later matching
617
+ resume. A mismatch is `INCONSISTENT`, preserves historical claims, and suspends
618
+ ordinary mutation until the protocol-owned evidence is repaired.
619
+
620
+ `CALLER_ACKNOWLEDGED` is not host attestation. `HOST_ATTESTED` requires a
621
+ host-owned `grantRef`; the standalone CLI does not self-issue that authority.
622
+
623
+ #### Canonical Fields
624
+
625
+ <!-- BEGIN FORGELOOP GENERATED: schema:task-recovery -->
626
+
627
+ - `schemaVersion` *(number, required, const: 1)*
628
+ - `protocolVersion` *(number, required, const: 1)*
629
+ - `taskId` *(string, required, minLength: 1)*
630
+ - `status` *(string, required, const: `RECOVERED`)*
631
+ - `recoveredAt` *(string, required)*
632
+ - `recoveryId` *(string, required, pattern: `^recovery-[A-Za-z0-9-]+$`)*
633
+ - `recoveryEventSeq` *(integer, required, minimum: 1)*
634
+ - `classificationAtRecovery` *(string, required, enum: `STALE`, `ABANDONED`, `LEGACY_BOUNDARY_MIGRATED`)*
635
+ - `reasonCodes` *(array<string>, required)*
636
+ - `releasedClaims` *(array<string>, required)*
637
+ - `previousPhase` *(string, required, minLength: 1)*
638
+ - `previousRevision` *(integer, required, minimum: 0)*
639
+ - `repositoryFingerprint` *(object, required)*
640
+ - `branch` *(string,null, required)*
641
+ - `head` *(string,null, required)*
642
+ - `authority` *(object, required)*
643
+ - `kind` *(string, required, enum: `CALLER_ACKNOWLEDGED`, `HOST_ATTESTED`)*
644
+ - `grantRef` *(string, optional, minLength: 1)*
645
+
646
+ <!-- END FORGELOOP GENERATED: schema:task-recovery -->
@@ -40,7 +40,7 @@ ForgeLoop uses a definition-driven command-line parser:
40
40
  | Category | Commands |
41
41
  | --- | --- |
42
42
  | **Inspection & Diagnostics** | [`protocol-info`](#protocol-info), [`doctor`](#doctor), [`progress`](#progress), [`profile-interview`](#profile-interview), [`inspect`](#inspect), [`status`](#status), [`validate-state`](#validate-state), [`validate-protocol`](#validate-protocol) |
43
- | **Setup & Maintenance** | [`init`](#init), [`update`](#update), [`task-migrate`](#task-migrate), [`migrate-protocol`](#migrate-protocol), [`task-unlock`](#task-unlock) |
43
+ | **Setup & Maintenance** | [`init`](#init), [`update`](#update), [`task-migrate`](#task-migrate), [`migrate-protocol`](#migrate-protocol), [`task-unlock`](#task-unlock), [`task-recover`](#task-recover), [`task-repair-legacy-recovery`](#task-repair-legacy-recovery), [`task-resume`](#task-resume) |
44
44
  | **Lifecycle & State** | [`activate`](#activate), [`route`](#route), [`preflight`](#preflight), [`advance`](#advance), [`next`](#next), [`record-diagnosis`](#record-diagnosis), [`record-decision-criterion`](#record-decision-criterion), [`complete`](#complete), [`clear-state`](#clear-state), [`reconcile-closure`](#reconcile-closure), [`task-create`](#task-create), [`task-list`](#task-list), [`task-show`](#task-show), [`task-lock-status`](#task-lock-status), [`task-scope`](#task-scope) |
45
45
  | **Cross-Harness Continuity** | [`continuity`](#continuity), [`record-continuity`](#record-continuity), [`reconcile-continuity`](#reconcile-continuity), [`clear-continuity`](#clear-continuity) |
46
46
  | **Verification & Completion** | [`prepare-completion`](#prepare-completion), [`run-check`](#run-check), [`record-check`](#record-check), [`record-terminal-result`](#record-terminal-result), [`audit`](#audit), [`report`](#report), [`validate-receipt`](#validate-receipt) |
@@ -1263,9 +1263,9 @@ protocol version.
1263
1263
 
1264
1264
  ### `task-unlock`
1265
1265
 
1266
- Forces the release of a stale task lock.
1266
+ Forces the release of a task lock or CAS-safely releases an unchanged stale lease.
1267
1267
 
1268
- - **Purpose**: Removes `.lock` file from the task directory when process crashed.
1268
+ - **Purpose**: Removes `.forgeloop/locks/<taskKey>.lock` when its owner is no longer valid. Prefer `--stale-only`; `--force` is an explicit unconditional maintenance action.
1269
1269
  - **Mutation**: Deletes task lock file.
1270
1270
  - **Options**:
1271
1271
 
@@ -1284,3 +1284,97 @@ Forces the release of a stale task lock.
1284
1284
  ```bash
1285
1285
  forgeloop task-unlock --task task-001 --force --json
1286
1286
  ```
1287
+
1288
+ ### `task-recover`
1289
+
1290
+ Suspends mutation and releases effective claims for a task deterministically classified `STALE` or `ABANDONED`.
1291
+
1292
+ - **Purpose**: For a task classified only `STALE` or `ABANDONED`, persists `recovery.json` plus a linked append-only event without changing work state or fabricating completion. The canonical claim-state resolver must validate both before claims become effective-empty. `RECOVERABLE` tasks must use `reconcile-closure`.
1293
+ - **Mutation**: Transactionally writes recovery state and appends the recovery event. Historical descriptor claims and all lifecycle evidence remain intact; ordinary mutations return `E_TASK_RECOVERED`.
1294
+ - **Options**:
1295
+
1296
+ <!-- BEGIN FORGELOOP GENERATED: cli:task-recover:options -->
1297
+
1298
+ - `--path <directory>`: target project directory (default: current directory)
1299
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1300
+ - `--acknowledge-recovery`: acknowledge release of claims for a STALE or ABANDONED task (required; not host attestation)
1301
+ - `--operator-authorized`: deprecated alias for --acknowledge-recovery; does not attest operator authority
1302
+ - `--json`: emit structured output as JSON
1303
+
1304
+ <!-- END FORGELOOP GENERATED: cli:task-recover:options -->
1305
+
1306
+ - **Example**:
1307
+
1308
+ ```bash
1309
+ forgeloop task-recover --task task-001 --acknowledge-recovery --json
1310
+ ```
1311
+
1312
+ `--acknowledge-recovery` is caller acknowledgement only. The deprecated
1313
+ `--operator-authorized` alias has the same semantics and is not host attestation.
1314
+ Fake, missing, corrupt, or mismatched recovery state is
1315
+ `E_TASK_CLAIM_OWNERSHIP_INCONSISTENT`/`E_TASK_RECOVERY_INCONSISTENT`; historical
1316
+ claims remain reserved.
1317
+
1318
+ ### `task-resume`
1319
+
1320
+ Reacquires a recovered task's write claims and restores ordinary mutation authority.
1321
+
1322
+ - **Purpose**: Validates active recovery ownership, CAS-settles only an unchanged stale task lease, reuses normal claim-overlap and clean-checkout enforcement under project/task serialization, then removes `recovery.json` transactionally.
1323
+ - **Mutation**: Optionally updates historical claims in `task.json`, appends `TASK_RECOVERY_RESUMED`, and removes `recovery.json` in one transaction.
1324
+ - **Options**:
1325
+
1326
+ <!-- BEGIN FORGELOOP GENERATED: cli:task-resume:options -->
1327
+
1328
+ - `--path <directory>`: target project directory (default: current directory)
1329
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1330
+ - `--claim <path>`: write claim to reacquire (defaults to all released claims) (repeatable)
1331
+ - `--json`: emit structured output as JSON
1332
+
1333
+ <!-- END FORGELOOP GENERATED: cli:task-resume:options -->
1334
+
1335
+ - **Example**:
1336
+
1337
+ ```bash
1338
+ forgeloop task-resume --task task-001 --claim src --claim tests --json
1339
+ ```
1340
+
1341
+ With no `--claim`, the command attempts to reacquire all claims recorded in the
1342
+ active recovery artifact. It returns `E_TASK_SCOPE_CONFLICT` without removing
1343
+ recovery state when another active task owns an overlapping path.
1344
+ The resume event counts as meaningful task activity. Never create, edit, or
1345
+ delete `recovery.json` manually to emulate this command.
1346
+
1347
+ ### `task-repair-legacy-recovery`
1348
+
1349
+ Migrates one recognized legacy recovery boundary event into the modern durable recovery representation.
1350
+
1351
+ - **Purpose**: Proves that a historical `OPERATOR_RECOVERY_RECORDED` without `recoveryId` marks the effective task boundary and materializes its modern representation as an append-only `LEGACY_RECOVERY_MIGRATION_RECORDED` event plus a transactional `recovery.json`. The original legacy event is never modified.
1352
+ - **Mutation**: Appends the migration event at the ledger tail and writes `recovery.json` in one transaction under project claims locking.
1353
+ - **Options**:
1354
+
1355
+ <!-- BEGIN FORGELOOP GENERATED: cli:task-repair-legacy-recovery:options -->
1356
+
1357
+ - `--path <directory>`: target project directory (default: current directory)
1358
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
1359
+ - `--acknowledge-recovery`: fresh explicit acknowledgement of the legacy boundary migration (required)
1360
+ - `--json`: emit structured output as JSON
1361
+
1362
+ <!-- END FORGELOOP GENERATED: cli:task-repair-legacy-recovery:options -->
1363
+
1364
+ - **Example**:
1365
+
1366
+ ```bash
1367
+ forgeloop task-repair-legacy-recovery --task task-001 --acknowledge-recovery --json
1368
+ ```
1369
+
1370
+ Only the exact known legacy signature is eligible; ambiguous, tampered, or
1371
+ post-boundary-active ledgers fail closed with
1372
+ `E_LEGACY_RECOVERY_MIGRATION_INVALID` and ownership stays INCONSISTENT. A
1373
+ `STALE` task lease is settled only through CAS-safe stale release when the
1374
+ observed lock is unchanged; `LIVE` locks refuse with `E_TASK_LOCKED`, and
1375
+ `UNKNOWN`/`CORRUPT` locks fail closed with the lock preserved — never delete a
1376
+ lock file manually to unblock this command. The repair is idempotent: an
1377
+ already repaired task returns `{repaired: 0, alreadyRepaired: true}` only when
1378
+ the whole canonical recovery relationship validates; any mismatch fails closed.
1379
+ The repair itself never releases claims directly; ownership becomes validated
1380
+ recovery state and ordinary mutation remains blocked until `task-resume`.