@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.
- package/.github/copilot-instructions.md +1 -0
- package/AGENTS.md +1 -0
- package/CLAUDE.md +1 -0
- package/DOCS_INDEX.md +7 -0
- package/EXECUTION_STATE.md +40 -0
- package/LOOP_ENGINEERING.md +54 -5
- package/LOOP_SYSTEM_DESIGN.md +22 -1
- package/PROTOCOL_INTEGRATION.md +41 -0
- package/README.md +38 -0
- package/TERMINOLOGY.md +15 -0
- package/THIRD_PARTY_NOTICES.md +15 -0
- package/THREAT_MODEL.md +20 -1
- package/docs/ARTIFACT_REFERENCE.md +43 -0
- package/docs/CLI_REFERENCE.md +97 -3
- package/docs/CROSS_HARNESS_CONTINUITY.md +23 -0
- package/docs/DOCUMENTATION_GUIDE.md +14 -0
- package/docs/GETTING_STARTED.md +1 -0
- package/docs/MCP.md +126 -0
- package/docs/RECIPES.md +82 -0
- package/docs/RELEASE_CHECKLIST_1_4.md +38 -0
- package/docs/RELEASE_CHECKLIST_1_5_MCP.md +78 -0
- package/docs/TROUBLESHOOTING.md +111 -1
- package/docs/UNIVERSAL_INTEGRATION.md +48 -0
- package/package.json +14 -3
- package/schemas/task-recovery.schema.json +61 -0
- package/src/cli.js +173 -347
- package/src/commands/audit.js +5 -0
- package/src/commands/inspect.js +6 -0
- package/src/commands/progress.js +6 -2
- package/src/commands/status.js +17 -0
- package/src/commands/task-create.js +39 -1
- package/src/commands/task-list.js +14 -1
- package/src/commands/task-lock-status.js +2 -2
- package/src/commands/task-recover.js +202 -0
- package/src/commands/task-repair-legacy-recovery.js +417 -0
- package/src/commands/task-resume.js +172 -0
- package/src/commands/task-scope.js +23 -4
- package/src/commands/task-show.js +18 -4
- package/src/commands/validate-protocol.js +19 -2
- package/src/core/artifact-registry.js +12 -0
- package/src/core/audit.js +20 -4
- package/src/core/bundles.js +15 -0
- package/src/core/cli-command-definitions.js +50 -4
- package/src/core/command-executors.js +387 -0
- package/src/core/command-input.js +107 -0
- package/src/core/command-runtime.js +106 -0
- package/src/core/completion-artifacts.js +2 -3
- package/src/core/completion-ownership.js +88 -0
- package/src/core/error-codes.js +118 -1
- package/src/core/events.js +130 -1
- package/src/core/filesystem.js +55 -6
- package/src/core/inspect.js +27 -0
- package/src/core/integration-invocation-policy.js +170 -0
- package/src/core/integration-limits.js +20 -0
- package/src/core/integration-resources.js +127 -0
- package/src/core/next-action-model.js +60 -0
- package/src/core/next-action.js +31 -0
- package/src/core/phase.js +2 -1
- package/src/core/project-root.js +21 -0
- package/src/core/protocol-info.js +13 -0
- package/src/core/reconcile-closure.js +32 -10
- package/src/core/recovery-history.js +116 -0
- package/src/core/schema-validation.js +1 -0
- package/src/core/task-claim-state.js +272 -0
- package/src/core/task-command.js +5 -1
- package/src/core/task-conflict-inspection.js +321 -0
- package/src/core/task-context.js +32 -29
- package/src/core/task-discovery.js +14 -1
- package/src/core/task-lock.js +216 -22
- package/src/core/task-paths.js +3 -2
- package/src/core/task-recovery-migration.js +192 -0
- package/src/core/task-recovery.js +205 -0
- package/src/core/task-scope.js +33 -1
- package/src/core/templates.js +1 -0
- package/src/core/transaction.js +28 -2
- 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)
|
package/EXECUTION_STATE.md
CHANGED
|
@@ -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.
|
package/LOOP_ENGINEERING.md
CHANGED
|
@@ -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/
|
|
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.
|
|
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.
|
|
1318
|
-
|
|
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.
|
package/LOOP_SYSTEM_DESIGN.md
CHANGED
|
@@ -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
|
|
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.
|
package/PROTOCOL_INTEGRATION.md
CHANGED
|
@@ -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. |
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -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
|
|
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 -->
|
package/docs/CLI_REFERENCE.md
CHANGED
|
@@ -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
|
|
1266
|
+
Forces the release of a task lock or CAS-safely releases an unchanged stale lease.
|
|
1267
1267
|
|
|
1268
|
-
- **Purpose**: Removes `.lock`
|
|
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`.
|