@cassiomc1/forgeloop 1.9.0 → 1.10.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 (57) hide show
  1. package/AGENT_COMPATIBILITY.md +15 -0
  2. package/DELEGATION_PROTOCOL.md +6 -0
  3. package/DOCS_INDEX.md +4 -2
  4. package/LOOP_ENGINEERING.md +13 -0
  5. package/LOOP_SYSTEM_DESIGN.md +33 -0
  6. package/ORCHESTRATOR_INTEGRATION.md +9 -0
  7. package/PROTOCOL_INTEGRATION.md +31 -0
  8. package/README.md +40 -0
  9. package/TERMINOLOGY.md +12 -0
  10. package/THREAT_MODEL.md +24 -0
  11. package/completions/_forgeloop +2 -1
  12. package/completions/forgeloop.bash +3 -1
  13. package/completions/forgeloop.fish +9 -1
  14. package/docs/ADVISORY_CONTEXT.md +174 -0
  15. package/docs/AGENT_PROTOCOL_SUMMARY.md +28 -2
  16. package/docs/ARTIFACT_REFERENCE.md +14 -0
  17. package/docs/CLI_REFERENCE.md +40 -0
  18. package/docs/CROSS_HARNESS_CONTINUITY.md +85 -0
  19. package/docs/DOCUMENTATION_GUIDE.md +7 -0
  20. package/docs/GETTING_STARTED.md +22 -0
  21. package/docs/KNOWLEDGE_SOURCES.md +10 -0
  22. package/docs/MCP.md +17 -1
  23. package/docs/RECIPES.md +80 -0
  24. package/docs/RELEASE_CHECKLIST.md +14 -0
  25. package/docs/TROUBLESHOOTING.md +54 -2
  26. package/docs/UNIVERSAL_INTEGRATION.md +60 -0
  27. package/package.json +2 -1
  28. package/schemas/handoff-envelope.schema.json +1 -0
  29. package/scripts/check-changelog-freshness.mjs +27 -3
  30. package/scripts/generate-agent-protocol-summary.mjs +18 -0
  31. package/src/cli.js +6 -0
  32. package/src/commands/handoff-accept.js +36 -0
  33. package/src/commands/handoff-list.js +28 -2
  34. package/src/commands/handoff-show.js +27 -2
  35. package/src/commands/reconcile-continuity.js +4 -0
  36. package/src/core/advisory-context/constants.js +74 -0
  37. package/src/core/advisory-context/provider.js +287 -0
  38. package/src/core/advisory-context/service.js +140 -0
  39. package/src/core/cli-command-definitions.js +17 -0
  40. package/src/core/command-executors.js +12 -0
  41. package/src/core/command-input.js +11 -1
  42. package/src/core/continuity-lint.js +89 -0
  43. package/src/core/continuity-reconciliation.js +16 -0
  44. package/src/core/continuity.js +10 -11
  45. package/src/core/error-codes.js +113 -0
  46. package/src/core/events.js +32 -0
  47. package/src/core/execution-profile-context.js +15 -1
  48. package/src/core/filesystem.js +18 -2
  49. package/src/core/handoff-acceptance.js +277 -0
  50. package/src/core/handoff.js +41 -8
  51. package/src/core/integration-invocation-policy.js +19 -2
  52. package/src/core/integration-resources.js +21 -1
  53. package/src/core/portable-context.js +103 -0
  54. package/src/core/protocol-info.js +18 -2
  55. package/src/core/runtime-context.js +31 -0
  56. package/src/integration.d.ts +116 -0
  57. package/src/integration.js +22 -0
@@ -950,6 +950,7 @@ completion, or authority evidence.
950
950
  - `phase` *(string, required, minLength: 1)*
951
951
  - `revision` *(integer, required, minimum: 0)*
952
952
  - `verificationCycle` *(integer, required, minimum: 1)*
953
+ - `workStateFingerprint` *(string, optional, pattern: `^[a-f0-9]{64}$`)*
953
954
  - `contractFingerprint` *(string, required, pattern: `^[a-f0-9]{64}$`)*
954
955
  - `routeFingerprint` *(string or null, required)*
955
956
  - `repositoryFingerprint` *(object, required)*
@@ -965,6 +966,19 @@ completion, or authority evidence.
965
966
 
966
967
  <!-- END FORGELOOP GENERATED: schema:handoff-envelope -->
967
968
 
969
+ The handoff `state` binds the immutable snapshot to the exact
970
+ `workStateFingerprint`, contract identity, route identity, selected-guide
971
+ context, repository branch/HEAD fingerprint, changed paths, and historical
972
+ write claims observed at creation. `HANDOFF_CREATED` records the envelope's
973
+ relationship to the task ledger. A later `HANDOFF_ACCEPTED` event records only
974
+ that one consumer operationally consumed the unchanged snapshot; it does not
975
+ transfer claims, create evidence, or grant authority.
976
+
977
+ Acceptance status is a derived projection from the immutable handoff, its
978
+ digest, and the validated event ledger. Acceptance fields are intentionally not
979
+ stored in the handoff JSON itself. Invalid or mismatched ledger history
980
+ projects `INCONSISTENT`, never a successful acceptance.
981
+
968
982
  ### 2.27 `task-state/<taskKey>/responsibility.json`
969
983
 
970
984
  <!-- forgeloop-doc: schema=responsibility artifact=.forgeloop/task-state/<task-key>/responsibility.json -->
@@ -66,6 +66,7 @@ error codes. Default output and default JSON remain unchanged.
66
66
  | **Durable Actions & Approvals** | [`run-action`](#run-action), [`action-propose`](#action-propose), [`action-record`](#action-record), [`action-show`](#action-show), [`action-reconcile`](#action-reconcile), [`action-verify`](#action-verify), [`action-authorize`](#action-authorize), [`approval-request`](#approval-request), [`approval-resolve`](#approval-resolve) |
67
67
  | **Policy & Auditing** | [`policy`](#policy), [`policy-discover`](#policy-discover), [`policy-status`](#policy-status), [`policy-diff`](#policy-diff), [`rule-verify`](#rule-verify), [`baseline`](#baseline), [`bundle`](#bundle) |
68
68
  | **workspace** | [`workspace-bind`](#workspace-bind), [`workspace-status`](#workspace-status) |
69
+ | **task** | [`handoff-accept`](#handoff-accept) |
69
70
  | **scope** | [`responsibility-set`](#responsibility-set), [`responsibility-status`](#responsibility-status) |
70
71
  | **attestation** | [`attestation-create`](#attestation-create), [`attestation-verify`](#attestation-verify), [`attestation-status`](#attestation-status), [`attestation-verify-range`](#attestation-verify-range) |
71
72
 
@@ -157,6 +158,9 @@ Lists immutable handoff snapshots for a task.
157
158
 
158
159
  - **Purpose**: Inspect existing handoff snapshots without changing them.
159
160
  - **Mutation**: Read-only.
161
+ - **Acceptance projection**: Derives `OPEN`, `ACCEPTED`, `UNBOUND`, or
162
+ `INCONSISTENT` from the validated event ledger. Invalid or unreadable ledgers
163
+ are fail-closed and expose `reasonCodes`; they are never treated as empty.
160
164
  - **Options**:
161
165
 
162
166
  <!-- BEGIN FORGELOOP GENERATED: cli:handoff-list:options -->
@@ -178,6 +182,8 @@ Lists immutable handoff snapshots for a task.
178
182
  Reads and verifies one immutable handoff snapshot.
179
183
 
180
184
  - **Purpose**: Inspect one handoff by ID and validate its digest and bindings.
185
+ - **Acceptance projection**: Uses the same fail-closed ledger-derived status as
186
+ `handoff-list`.
181
187
  - **Mutation**: Read-only.
182
188
  - **Options**:
183
189
 
@@ -196,6 +202,37 @@ Reads and verifies one immutable handoff snapshot.
196
202
  forgeloop handoff-show --task task-001 --id handoff-001 --json
197
203
  ```
198
204
 
205
+ ### `handoff-accept`
206
+
207
+ Records exactly-once acceptance of an immutable handoff into the task event ledger.
208
+
209
+ - **Purpose**: Bind an incoming consumer/harness to an immutable handoff snapshot.
210
+ - **Mutation**: Appends a `HANDOFF_ACCEPTED` event.
211
+ - **Freshness**: Acceptance requires the current canonical state and directly
212
+ observed repository branch/HEAD to match the immutable snapshot, including a
213
+ clean committed HEAD drift check.
214
+ - **Human output**: Reports `authority: OPERATIONAL_RECEIPT_ONLY`,
215
+ `evidence: NONE`, and `claims transferred: NO`; acceptance is exactly-once
216
+ operational receipt only.
217
+ - **Options**:
218
+
219
+ <!-- BEGIN FORGELOOP GENERATED: cli:handoff-accept:options -->
220
+
221
+ - `--path <directory>`: target project directory (default: current directory)
222
+ - `--task <id>`: task ID to operate on (when omitted, resolved from context or single active task)
223
+ - `--handoff <id>`: handoff identifier
224
+ - `--consumer-id <id>`: consumer identifier accepting the handoff
225
+ - `--harness <name>`: optional harness accepting the handoff
226
+ - `--json`: emit acceptance result as JSON
227
+
228
+ <!-- END FORGELOOP GENERATED: cli:handoff-accept:options -->
229
+
230
+ - **Example**:
231
+
232
+ ```bash
233
+ forgeloop handoff-accept --task task-001 --handoff handoff-001 --consumer-id agent-42 --json
234
+ ```
235
+
199
236
  ### `responsibility-set`
200
237
 
201
238
  Creates immutable constraints for the current task pass.
@@ -914,6 +951,9 @@ Records operational handoff context before pausing or switching tools.
914
951
  Reconciles continuity with the active work state and checkout.
915
952
 
916
953
  - **Purpose**: Compares continuity bindings against the canonical work state, contract, phase, repository fingerprint, and checkout state.
954
+ - **Lint**: Returns deterministic `PASS`/`WARN` findings for stale completed
955
+ item references, role conflicts, missing `inspectFirst` paths, and empty hint
956
+ sets without changing reconciliation classification.
917
957
  - **When to use**: When starting a session in an active task.
918
958
  - **Mutation**: Read-only.
919
959
  - **Options**:
@@ -114,6 +114,33 @@ exists, compare the current checkout, and only then follow `forgeloop next`.
114
114
  Handoff notes can focus inspection, but only valid execution evidence,
115
115
  completion receipts, and the append-only ledger can satisfy verification.
116
116
 
117
+ The complete immutable-handoff flow is:
118
+
119
+ ```bash
120
+ forgeloop handoff-create --task auth-feature --recipient codex --json
121
+ forgeloop handoff-list --task auth-feature --json
122
+ forgeloop handoff-show --task auth-feature --id <handoff-id> --json
123
+ forgeloop handoff-accept \
124
+ --task auth-feature \
125
+ --handoff <handoff-id> \
126
+ --consumer-id codex-session-42 \
127
+ --harness codex \
128
+ --json
129
+ ```
130
+
131
+ Before acceptance, the receiver must inspect the immutable snapshot and
132
+ reconcile all of its freshness bindings: the work-state fingerprint, contract
133
+ identity, route identity, selected guides, current repository branch, current
134
+ repository HEAD, changed paths, and the origin of the event ledger. Receiving a
135
+ file or message is not acceptance. `handoff-accept` is run only when the
136
+ receiving harness actually consumes the handoff.
137
+
138
+ Acceptance retry semantics are deterministic: retrying with the same
139
+ `consumerId` returns the existing operational receipt idempotently; a different
140
+ consumer fails with `E_HANDOFF_ALREADY_ACCEPTED`. An old unbound handoff remains
141
+ readable for historical continuity but is not acceptable and returns
142
+ `E_HANDOFF_ACCEPTANCE_UNBOUND`.
143
+
117
144
  ---
118
145
 
119
146
  ## 4. Harness A — Recording Handoff Context
@@ -251,3 +278,61 @@ Every discovery adapter (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/project-loop.m
251
278
  > Discover task namespaces with ForgeLoop; if exactly one active task is healthy it may be selected implicitly; if multiple active tasks exist, select with `--task` or `FORGELOOP_TASK`.
252
279
  > Inspect the existing task, reconcile continuity when present, inspect the checkout, and run `forgeloop next`.
253
280
  > A change of harness, model, provider, IDE, process, terminal, or session does not create a new task.
281
+
282
+ ---
283
+
284
+ ## 8. Canonical Handoff Acceptance & State Binding
285
+
286
+ ### 8.1 Work-State Binding
287
+
288
+ Handoff envelopes (`.forgeloop/task-state/<taskKey>/handoffs/handoff-*.json`) bind to the exact lifecycle state snapshot at creation time via `state.workStateFingerprint`.
289
+ The envelope itself remains strictly immutable after creation.
290
+ A handoff is acceptable only when both canonical state and the current repository
291
+ checkout still match that immutable snapshot. A clean Git HEAD or branch change
292
+ can make a handoff stale even when the worktree has no uncommitted changes.
293
+
294
+ ### 8.2 Exactly-Once Handoff Acceptance
295
+
296
+ Harnesses taking ownership of an existing handoff record their acceptance into the task event ledger using `handoff-accept`:
297
+
298
+ ```bash
299
+ forgeloop handoff-accept \
300
+ --task auth-feature \
301
+ --handoff handoff-001 \
302
+ --consumer-id agent-session-42 \
303
+ --harness cursor \
304
+ --json
305
+ ```
306
+
307
+ Acceptance enforces:
308
+
309
+ 1. **Unbroken Binding**: Handoff must contain `workStateFingerprint` (legacy unbound handoffs fail with `E_HANDOFF_ACCEPTANCE_UNBOUND`).
310
+ 2. **Freshness**: Work state, contract fingerprint, route fingerprint, changed paths, and the directly observed current repository branch and HEAD must match the handoff snapshot (any drift fails with `E_HANDOFF_STALE`).
311
+ 3. **Single Consumer**: The handoff can be accepted by at most one consumer. If another consumer attempts acceptance, it fails with `E_HANDOFF_ALREADY_ACCEPTED`. Retrying with the same `consumerId` is idempotent.
312
+ 4. **Ledger Integrity**: An immutable `HANDOFF_ACCEPTED` event is appended to `events.ndjson`.
313
+
314
+ Acceptance is exactly-once operational receipt only. It does not transfer claims,
315
+ delegate work, authorize actions, approve review, or create verification evidence.
316
+
317
+ ### 8.3 Acceptance Inspection
318
+
319
+ Commands `handoff-show` and `handoff-list` project current acceptance status:
320
+
321
+ - `OPEN`: Handoff is valid, bound, and waiting for acceptance.
322
+ - `ACCEPTED`: Successfully accepted by a specific consumer.
323
+ - `UNBOUND`: Legacy handoff envelope lacking work-state binding.
324
+ - `INCONSISTENT`: Digest, ledger validation, or acceptance event mismatch detected. An unreadable or invalid ledger is never projected as `OPEN` or `ACCEPTED`; its unique sorted ledger error codes are exposed as `reasonCodes`.
325
+
326
+ ### 8.4 Semantic Continuity Linting
327
+
328
+ When running `forgeloop reconcile-continuity`, ForgeLoop executes deterministic
329
+ semantic lint checks against schema-valid operational hints. It warns when a
330
+ remaining-work item or current focus ID is already in `state.completedSteps`,
331
+ when an ID appears in both `remainingWork` and `knownIssues`, or when a relative
332
+ `inspectFirst` path is missing from the target. If all operational hints are
333
+ empty, it emits the informational `CONTINUITY_EMPTY_HINT_SET` finding while the
334
+ lint status remains `PASS`.
335
+
336
+ Lint results use `{ status: "PASS" | "WARN", findings: [...] }`. They are
337
+ non-authoritative, non-evidence diagnostics and do not change reconciliation
338
+ classification or lifecycle state.
@@ -38,6 +38,13 @@ MCP package boundary -> MCP package tests + scripts/mcp-package-smoke.mjs
38
38
 
39
39
  Operational documentation must explain canonical behavior, not redefine it.
40
40
 
41
+ Terminology must remain consistent across active documents: say “advisory
42
+ context,” not “canonical memory”; “handoff acceptance,” not “ownership
43
+ transfer”; and “operational receipt,” not “delegation.” Advisory output is
44
+ never canonical state, evidence, authority, completion truth, or next-action
45
+ authority. `consumerId`, harness names, recipient hints, and transport labels
46
+ are descriptive values rather than authenticated identity or authority.
47
+
41
48
  Documentation-impact questions for integration/MCP changes:
42
49
 
43
50
  - Did a server mode or capability gate change?
@@ -439,6 +439,8 @@ the workflow needs those boundaries:
439
439
  forgeloop handoff-create --task <taskId> --note "Continue verification" --json
440
440
  forgeloop handoff-list --task <taskId> --json
441
441
  forgeloop handoff-show --task <taskId> --id <handoffId> --json
442
+ forgeloop handoff-accept --task <taskId> --handoff <handoffId> \
443
+ --consumer-id <consumerId> --harness <harness> --json
442
444
  forgeloop responsibility-set --task <taskId> --label implementation --allowed-path src --required-check unit-tests --json
443
445
  forgeloop responsibility-status --task <taskId> --json
444
446
  ```
@@ -450,6 +452,26 @@ not delegation or evidence. A responsibility label is descriptive, not a
450
452
  coder/reviewer/cleaner role, and its allowed paths, required checks, and frozen
451
453
  inputs are mechanically enforced when present.
452
454
 
455
+ ### Optional advisory context
456
+
457
+ An embedding host may inject an advisory provider through the Integration API
458
+ when extra context is useful. This is not part of the minimum quickstart:
459
+
460
+ ```javascript
461
+ const runtimeContext = createForgeLoopContext({
462
+ advisoryContextProviders: {
463
+ "host-context": {
464
+ id: "host-context",
465
+ recall: async ({ query }) => ({ items: await hostLookup(query) }),
466
+ },
467
+ },
468
+ });
469
+ ```
470
+
471
+ Recall is explicit, lazy, bounded, and non-persisted. Provider output is never
472
+ state, evidence, authority, completion truth, or executable instructions. See
473
+ [`ADVISORY_CONTEXT.md`](./ADVISORY_CONTEXT.md) for the full contract.
474
+
453
475
  ### Differential Verification Scope
454
476
 
455
477
  Configure a trusted scoped checker only when it can consume canonical paths:
@@ -8,6 +8,16 @@ Target: ForgeLoop 1.8.0 at current `main` state at review start
8
8
  This ledger records research inputs for the knowledge-integration review. It is
9
9
  not an endorsement list, a source-content mirror, or an evidence registry.
10
10
 
11
+ ## Current optional provider source class
12
+
13
+ This note is an operational boundary added after the historical snapshot above;
14
+ it does not rewrite that review's target version or accepted sources. A host may
15
+ provide external advisory context through the ForgeLoop Integration API, but a
16
+ knowledge source is not canonical task state, evidence, authority, completion,
17
+ or next-action authority. Provider results remain lazy, opt-in, bounded, and
18
+ non-persisted; provenance belongs to the host unless a separately versioned
19
+ canonical artifact is introduced.
20
+
11
21
  ## User-provided revised plan
12
22
 
13
23
  Source: user-provided `FORGELOOP_LUNA_KNOWLEDGE_INTEGRATION_PLAN_REVISED.md`
package/docs/MCP.md CHANGED
@@ -25,6 +25,9 @@ Two transports ship in one package:
25
25
  - **Recovery acknowledgement is not authorization.** `acknowledgeRecovery`
26
26
  in tool input only satisfies ForgeLoop's caller acknowledgement after the
27
27
  server was started with recovery capability.
28
+ - **Advisory context is host-injected only.** The core Integration API supports
29
+ explicit provider injection, but the stock MCP adapter must not fabricate,
30
+ auto-discover, or persist an advisory provider or its results.
28
31
 
29
32
  ## Modes
30
33
 
@@ -84,6 +87,19 @@ content.
84
87
  Raw recovery artifacts, transaction journals, lock files, and unbounded event
85
88
  ledgers are intentionally not exposed.
86
89
 
90
+ The `handoff-accept` mutating command is available only through a mode that
91
+ allows loop mutations; `readonly` intentionally hides it. When exposed, it
92
+ records one canonical `HANDOFF_ACCEPTED` operational receipt and preserves the
93
+ same freshness, consumer-idempotency, ledger, and no-claim-transfer rules as
94
+ the CLI and Integration API. MCP transport metadata cannot authenticate a
95
+ `consumerId`, establish authority, or turn receipt of a message into
96
+ acceptance.
97
+
98
+ Advisory provider recall is not a stock MCP resource or command. A host that
99
+ needs advisory context injects a provider into the core Integration API and
100
+ performs an explicit bounded recall itself. MCP must never auto-recall context
101
+ for startup, status, next, task/context, or any other canonical projection.
102
+
87
103
  The context resource is read-only. It lets an MCP host adapt presentation depth
88
104
  from the canonical resolved execution profile while preserving lifecycle
89
105
  phases, required gates, verification truth, authority, provenance, and
@@ -119,7 +135,7 @@ forgeloop-mcp-http --project /repo --mode safe # 127.0.0.1:3333
119
135
 
120
136
  | Component | Current contract |
121
137
  | --- | --- |
122
- | ForgeLoop core package | `>=1.5.0 <2` dependency range; current repository generation `1.9.x` |
138
+ | ForgeLoop core package | `>=1.5.0 <2` dependency range; current release `1.10.0` |
123
139
  | ForgeLoop protocol | `1` |
124
140
  | Integration API | `1` |
125
141
  | MCP package | `0.1.x` initial package |
package/docs/RECIPES.md CHANGED
@@ -457,6 +457,86 @@ operational context only: a handoff is not delegation, authority, independent
457
457
  review evidence, or completion evidence. Use `continuity.json` for mutable
458
458
  resume notes and canonical execution artifacts for proof.
459
459
 
460
+ ### Recipe 18A — Accept an Immutable Handoff Exactly Once
461
+
462
+ After inspecting the snapshot and confirming that the receiving harness is
463
+ actually consuming it, record the operational receipt:
464
+
465
+ ```bash
466
+ forgeloop handoff-accept --task task-001 \
467
+ --handoff <handoffId> \
468
+ --consumer-id agent-session-42 \
469
+ --harness codex \
470
+ --json
471
+ ```
472
+
473
+ Retrying with the same consumer is idempotent. A different consumer receives
474
+ `E_HANDOFF_ALREADY_ACCEPTED`. Acceptance is operational only: it does not
475
+ transfer claims, create evidence, approve delegation, or grant authority.
476
+
477
+ ### Recipe 18B — Diagnose an Inconsistent Handoff
478
+
479
+ Inspect the derived projection and ledger before attempting any repair:
480
+
481
+ ```bash
482
+ forgeloop handoff-list --task task-001 --json
483
+ forgeloop handoff-show --task task-001 --id <handoffId> --json
484
+ forgeloop validate-protocol --task task-001 --json
485
+ ```
486
+
487
+ `INCONSISTENT` is fail-closed. Check the returned reason codes for a stale
488
+ contract/route/repository snapshot, an unbound legacy handoff, a digest mismatch,
489
+ or invalid acceptance history. Do not edit the immutable handoff or
490
+ `events.ndjson`; create a fresh handoff after the canonical issue is resolved.
491
+
492
+ ### Recipe 18C — Use an Advisory Provider from a Host Integration
493
+
494
+ Register a provider in runtime context and invoke recall explicitly:
495
+
496
+ ```javascript
497
+ import {
498
+ createForgeLoopContext,
499
+ recallAdvisoryContext,
500
+ } from "@cassiomc1/forgeloop/integration";
501
+
502
+ const runtimeContext = createForgeLoopContext({
503
+ advisoryContextProviders: {
504
+ "host-context": {
505
+ id: "host-context",
506
+ recall: async ({ query }) => ({ items: await hostLookup(query) }),
507
+ },
508
+ },
509
+ });
510
+
511
+ const result = await recallAdvisoryContext({
512
+ target: ".",
513
+ taskId: "task-001",
514
+ providerName: "host-context",
515
+ query: "current authentication constraints",
516
+ runtimeContext,
517
+ });
518
+ ```
519
+
520
+ Recall is lazy, bounded, opt-in, non-persisted, non-evidence, and
521
+ non-executable. Validate every proposed change against canonical state and
522
+ verification instead of executing provider text.
523
+
524
+ ### Recipe 18D — Resume with Continuity Lint Warnings
525
+
526
+ Treat lint findings as inspection hints only:
527
+
528
+ ```bash
529
+ forgeloop continuity --task task-001 --json
530
+ forgeloop reconcile-continuity --task task-001 --json
531
+ forgeloop next --task task-001 --json
532
+ ```
533
+
534
+ Findings such as `CONTINUITY_REMAINING_ALREADY_COMPLETED`,
535
+ `CONTINUITY_FOCUS_ALREADY_COMPLETED`, `CONTINUITY_ITEM_ROLE_CONFLICT`,
536
+ `CONTINUITY_INSPECT_PATH_MISSING`, and `CONTINUITY_EMPTY_HINT_SET` are
537
+ non-authoritative and non-evidence. Refresh the note with
538
+ `record-continuity` when useful, then follow the canonical next action.
539
+
460
540
  ---
461
541
 
462
542
  ### Recipe 19 — Apply a Responsibility Contract
@@ -16,6 +16,20 @@ preparation and verification checklist; it does not authorize publication.
16
16
 
17
17
  ## Protocol and attestation
18
18
 
19
+ - [ ] `protocol-info` and the Integration API capability contracts agree.
20
+ - [ ] `canonicalHandoffs` v2 is advertised consistently.
21
+ - [ ] `advisoryContextProviders` v1 is advertised consistently.
22
+ - [ ] Advisory context remains Integration-API-only.
23
+ - [ ] `next`, `status`, and `task/context` invoke zero advisory providers.
24
+ - [ ] Advisory request budgets are normalized before provider invocation.
25
+ - [ ] Advisory results are never persisted by ForgeLoop.
26
+ - [ ] Same-consumer handoff acceptance is idempotent.
27
+ - [ ] Different-consumer handoff acceptance fails closed.
28
+ - [ ] Concurrent acceptance creates one `HANDOFF_ACCEPTED` event.
29
+ - [ ] Clean HEAD/branch drift rejects handoff acceptance.
30
+ - [ ] Stale contract/route identity rejects handoff creation or acceptance.
31
+ - [ ] An invalid event ledger projects `INCONSISTENT`.
32
+ - [ ] Continuity lint remains non-authoritative and non-evidence.
19
33
  - [ ] `npm run dependency:policy` passes without adding runtime dependencies.
20
34
  - [ ] `npm run lint` passes.
21
35
  - [ ] `npm test` passes.
@@ -761,16 +761,50 @@ explicit operation only when the task's scope permits it.
761
761
 
762
762
  ---
763
763
 
764
+ ### Symptom: Advisory Context Recall Is Unavailable or Rejected
765
+
766
+ #### Error Codes: `E_ADVISORY_CONTEXT_PROVIDER_INVALID`, `E_ADVISORY_CONTEXT_PROVIDER_UNAVAILABLE`, `E_ADVISORY_CONTEXT_QUERY_INVALID`, `E_ADVISORY_CONTEXT_REQUEST_INVALID`, `E_ADVISORY_CONTEXT_RESULT_INVALID`, `E_ADVISORY_CONTEXT_TIMEOUT`, `E_ADVISORY_CONTEXT_OUTPUT_LIMIT`, `E_PORTABLE_CONTEXT_INVALID`
767
+
768
+ #### What it means
769
+
770
+ The host's optional advisory provider is missing, malformed, unavailable, too
771
+ slow, or returned content outside the bounded portable-context contract. These
772
+ failures never become lifecycle, evidence, completion, or next-action failures.
773
+
774
+ #### Safe recovery
775
+
776
+ Inspect provider registration and normalize the request before retrying through
777
+ the Integration API. Reduce query, item, total-output, and timeout values to the
778
+ documented budgets, remove secrets/control characters, and ensure the provider
779
+ returns only allowlisted item fields. If advisory context is unavailable,
780
+ continue from canonical task state; do not fabricate a provider or execute its
781
+ text.
782
+
783
+ ### Symptom: Continuity Lint Reports a Contradictory Hint
784
+
785
+ Continuity lint is diagnostic only. Its findings do not change reconciliation,
786
+ state, evidence, authority, or completion:
787
+
788
+ | Finding | Meaning | Safe response |
789
+ | --- | --- | --- |
790
+ | `CONTINUITY_REMAINING_ALREADY_COMPLETED` | A remaining-work item is already recorded as completed. | Refresh the operational note; do not change canonical completion evidence. |
791
+ | `CONTINUITY_FOCUS_ALREADY_COMPLETED` | The current focus ID is already completed. | Choose a current inspection focus or clear the hint. |
792
+ | `CONTINUITY_ITEM_ROLE_CONFLICT` | An item appears in both remaining work and known issues. | Remove the contradictory hint through `record-continuity`. |
793
+ | `CONTINUITY_INSPECT_PATH_MISSING` | An `inspectFirst` path is not present in the current target. | Reconcile the checkout and update the path hint. |
794
+ | `CONTINUITY_EMPTY_HINT_SET` | No operational hint was supplied. | Treat the result as informational and follow canonical `next`. |
795
+
764
796
  ### Symptom: Handoff Is Invalid or Tampered
765
797
 
766
- #### Error Codes: `E_HANDOFF_INVALID`, `E_HANDOFF_STATE_UNAVAILABLE`, `E_HANDOFF_TAMPERED`, `E_HANDOFF_NOT_FOUND`
798
+ #### Error Codes: `E_HANDOFF_INVALID`, `E_HANDOFF_STATE_UNAVAILABLE`, `E_HANDOFF_TAMPERED`, `E_HANDOFF_NOT_FOUND`, `E_HANDOFF_STALE`, `E_HANDOFF_ALREADY_ACCEPTED`, `E_HANDOFF_ACCEPTANCE_INCONSISTENT`
767
799
 
768
800
  #### What it means
769
801
 
770
802
  The immutable handoff envelope is malformed, its state is unavailable, its
771
803
  digest no longer matches, or the requested snapshot does not exist. A handoff
772
804
  note is not delegation, authority, independent review evidence, or completion
773
- evidence.
805
+ evidence. Acceptance is exactly-once operational receipt only. The current
806
+ repository branch and HEAD are checked directly, so clean committed checkout
807
+ drift can make a handoff stale even when changed paths are empty.
774
808
 
775
809
  #### Safe recovery
776
810
 
@@ -781,6 +815,12 @@ forgeloop continuity --task <id> --json
781
815
  forgeloop reconcile-continuity --task <id> --json
782
816
  ```
783
817
 
818
+ If `handoff-list` or `handoff-show` reports `INCONSISTENT`, inspect the
819
+ `reasonCodes` field. The commands validate the event ledger before projecting
820
+ acceptance and never turn an unreadable or invalid ledger into an empty ledger.
821
+ Repair the named ledger through the canonical protocol workflow; do not edit
822
+ `events.ndjson` by hand.
823
+
784
824
  Use the last valid handoff or continuity only to focus inspection, then trust
785
825
  the canonical task state and checkout. Never repair a handoff by editing or
786
826
  deleting its JSON file.
@@ -1002,6 +1042,13 @@ current-cycle validation.
1002
1042
  | `E_ACTION_STATE_MISMATCH` | Requested durable action transition is not part of the canonical state machine. | Inspect current action state with forgeloop action-show and use a legal transition; never edit action artifacts by hand. |
1003
1043
  | `E_ACTION_VERIFICATION_INVALID` | Verification evidence does not resolve to a canonical passed ForgeLoop artifact bound to this task and action. | Supply a canonical execution or check reference produced by run-check for this task; arbitrary strings fail closed. |
1004
1044
  | `E_ACTION_VERIFICATION_REQUIRED` | The action cannot reach VERIFIED through this surface; canonical independent postcondition evidence is required. | Run an independent verification check, then record it with forgeloop action-verify; exit code 0 alone is not verification. |
1045
+ | `E_ADVISORY_CONTEXT_OUTPUT_LIMIT` | Advisory context output exceeded the configured character or item limit. | Reduce query scope, limit items, or truncate oversized summaries at the provider. |
1046
+ | `E_ADVISORY_CONTEXT_PROVIDER_INVALID` | Advisory context provider configuration or interface implementation is invalid. | Use a provider implementing id, recall(input) with bounded query parameters; advisory context is optional. |
1047
+ | `E_ADVISORY_CONTEXT_PROVIDER_UNAVAILABLE` | Requested advisory context provider is not registered in runtime context. | Register the provider in runtime context before recall, or proceed without advisory context; provider failure never blocks canonical lifecycle. |
1048
+ | `E_ADVISORY_CONTEXT_QUERY_INVALID` | Advisory context query failed portable-context validation or exceeded budget. | Provide a bounded query free of control characters and secret-like values. |
1049
+ | `E_ADVISORY_CONTEXT_REQUEST_INVALID` | Advisory context recall budgets are not finite integer values within the supported request contract. | Provide finite integer limit, maxItemChars, maxTotalChars, and timeoutMs values; oversized valid values are clamped to documented maxima. |
1050
+ | `E_ADVISORY_CONTEXT_RESULT_INVALID` | Advisory context provider returned an invalid result structure. | Ensure provider returns items with string summary and optional title, sourceRef, observedAt, confidence. |
1051
+ | `E_ADVISORY_CONTEXT_TIMEOUT` | Advisory context recall exceeded its execution timeout. | Use a responsive provider or increase timeout within limits; advisory context is optional. |
1005
1052
  | `E_APPROVAL_ALREADY_RESOLVED` | Approval is one-time resolvable and has already been approved or rejected. | Request a new approval if another decision is required. |
1006
1053
  | `E_APPROVAL_INVALID` | Approval artifact is malformed or does not bind the required fingerprint tuple. | Request a new approval with forgeloop approval-request; never hand-edit approval artifacts. |
1007
1054
  | `E_APPROVAL_STALE` | Approval no longer matches the current action fingerprint, contract fingerprint, task revision, or capability. | Request and resolve a fresh approval against the current action revision. |
@@ -1090,8 +1137,12 @@ current-cycle validation.
1090
1137
  | `E_GATE_REQUIRED` | A ForgeLoop protocol validation or lifecycle condition was not satisfied. | Inspect the structured command result, correct the named artifact or prerequisite, then run forgeloop next --json. |
1091
1138
  | `E_GATE_STALE` | Referenced gate artifact changed after approval. | Update artifact SHA-256 in gate file. |
1092
1139
  | `E_GATE_UNVERIFIED` | A ForgeLoop protocol validation or lifecycle condition was not satisfied. | Inspect the structured command result, correct the named artifact or prerequisite, then run forgeloop next --json. |
1140
+ | `E_HANDOFF_ACCEPTANCE_INCONSISTENT` | Handoff acceptance disagrees with task event ledger history. | Verify ledger integrity and require a preceding valid HANDOFF_CREATED event. |
1141
+ | `E_HANDOFF_ACCEPTANCE_UNBOUND` | Handoff snapshot lacks required workStateFingerprint binding. | Create a fresh handoff from the current ForgeLoop version before accepting it. |
1142
+ | `E_HANDOFF_ALREADY_ACCEPTED` | Handoff was already accepted by a different consumer. | Create a new handoff for the new consumer; do not manually edit acceptance events. |
1093
1143
  | `E_HANDOFF_INVALID` | A ForgeLoop boundary, artifact, provider, or attestation validation condition was not satisfied. | Inspect the structured command result, correct the named boundary or artifact, then retry the canonical command. |
1094
1144
  | `E_HANDOFF_NOT_FOUND` | A ForgeLoop boundary, artifact, provider, or attestation validation condition was not satisfied. | Inspect the structured command result, correct the named boundary or artifact, then retry the canonical command. |
1145
+ | `E_HANDOFF_STALE` | Handoff snapshot has drifted from the current canonical task state or repository. | Create a new fresh handoff from the current task state instead of accepting a stale snapshot. |
1095
1146
  | `E_HANDOFF_STATE_UNAVAILABLE` | A ForgeLoop boundary, artifact, provider, or attestation validation condition was not satisfied. | Inspect the structured command result, correct the named boundary or artifact, then retry the canonical command. |
1096
1147
  | `E_HANDOFF_TAMPERED` | A ForgeLoop boundary, artifact, provider, or attestation validation condition was not satisfied. | Inspect the structured command result, correct the named boundary or artifact, then retry the canonical command. |
1097
1148
  | `E_HYPOTHESIS_DISPOSITION_EVIDENCE_INVALID` | Hypothesis disposition evidence references do not resolve to checks of the active cycle. | Reference at least one check ID recorded in the active verification cycle. |
@@ -1124,6 +1175,7 @@ current-cycle validation.
1124
1175
  | `E_POLICY_PROOF_STALE` | Mutation verification proof is stale due to checker or fixture modifications. | Re-run forgeloop rule-verify to refresh mutation proof. |
1125
1176
  | `E_POLICY_SNAPSHOT_WRITE_FAILED` | Failed to persist task policy snapshot during preflight. | Ensure the target task directory is writable and repair filesystem permissions. |
1126
1177
  | `E_POLICY_WEAKENING` | Policy rules were weakened during task execution without explicit authority. | Restore the original policy configuration. |
1178
+ | `E_PORTABLE_CONTEXT_INVALID` | Text or object failed portable-context safety, character, or secret limits. | Ensure text is bounded, contains no control characters, and contains no secret-like values. |
1127
1179
  | `E_PREFLIGHT_EVENT_MISSING` | A ForgeLoop protocol validation or lifecycle condition was not satisfied. | Inspect the structured command result, correct the named artifact or prerequisite, then run forgeloop next --json. |
1128
1180
  | `E_PREFLIGHT_GATES_STALE` | A ForgeLoop protocol validation or lifecycle condition was not satisfied. | Inspect the structured command result, correct the named artifact or prerequisite, then run forgeloop next --json. |
1129
1181
  | `E_PREFLIGHT_GATE_EVENT_MISSING` | A ForgeLoop protocol validation or lifecycle condition was not satisfied. | Inspect the structured command result, correct the named artifact or prerequisite, then run forgeloop next --json. |
@@ -93,6 +93,66 @@ commands in [`EXECUTION_PROFILE_BENCHMARKS.md`](./EXECUTION_PROFILE_BENCHMARKS.m
93
93
  The benchmark source policy accepts provider or host observations only and
94
94
  keeps unavailable or non-comparable measurements out of efficiency claims.
95
95
 
96
+ ### Advisory Context & Handoff Acceptance
97
+
98
+ Capability negotiation is feature-first: `canonicalHandoffs` is v2 and
99
+ `advisoryContextProviders` is v1. These capability-family versions are
100
+ independent of Protocol v1, schema v1, and Integration API v1. The programmatic
101
+ integration API exposes lazy advisory context querying and exactly-once handoff
102
+ acceptance:
103
+
104
+ ```javascript
105
+ import {
106
+ createForgeLoopContext,
107
+ recallAdvisoryContext,
108
+ acceptCanonicalHandoff,
109
+ resolveHandoffAcceptance,
110
+ } from "@cassiomc1/forgeloop/integration";
111
+
112
+ // 1. Register host-provided advisory context
113
+ const runtimeContext = createForgeLoopContext({
114
+ advisoryContextProviders: {
115
+ "host-memory": {
116
+ id: "host-memory",
117
+ recall: async ({ query }) => ({ items: [...] }),
118
+ },
119
+ },
120
+ });
121
+
122
+ // 2. Explicitly query advisory context (strictly non-evidence, non-executable)
123
+ const advisoryResult = await recallAdvisoryContext({
124
+ target: ".",
125
+ taskId: "task-1",
126
+ providerName: "host-memory",
127
+ query: "authentication tokens",
128
+ runtimeContext,
129
+ });
130
+
131
+ // 3. Exactly-once handoff acceptance
132
+ const acceptance = await acceptCanonicalHandoff(".", {
133
+ taskId: "task-1",
134
+ handoffId: "handoff-001",
135
+ consumerId: "agent-session-42",
136
+ harness: "cursor",
137
+ });
138
+ ```
139
+
140
+ See [`ADVISORY_CONTEXT.md`](./ADVISORY_CONTEXT.md) for full trust boundary specifications, portable text sanitization rules, and budget enforcement.
141
+
142
+ Advisory recall budgets are normalized before provider dispatch: valid oversized
143
+ integer requests are clamped, while invalid finite/integer/minimum types fail
144
+ with `E_ADVISORY_CONTEXT_REQUEST_INVALID` before provider lookup. The registry
145
+ key and resolved provider `id` must match. Handoff acceptance independently
146
+ checks canonical state and the current repository branch/HEAD, and remains an
147
+ exactly-once operational receipt with no evidence, claim transfer, or authority.
148
+
149
+ Advisory context is not a canonical resource unless a future explicitly
150
+ versioned resource introduces one. `protocol-info` advertises the optional
151
+ provider capability, but the stock CLI never recalls it automatically and
152
+ there is no stock `context-recall` command. A consumer that only understands
153
+ `canonicalHandoffs` v1 may disable only the handoff-specific UI while retaining
154
+ the rest of Protocol v1 functionality.
155
+
96
156
  ## Consumers
97
157
 
98
158
  | Surface | Entry |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cassiomc1/forgeloop",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Portable, verifiable engineering protocol for AI coding environments and developer workflows",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,6 +51,7 @@
51
51
  "docs/assets/diagrams",
52
52
  "docs/GETTING_STARTED.md",
53
53
  "docs/CROSS_HARNESS_CONTINUITY.md",
54
+ "docs/ADVISORY_CONTEXT.md",
54
55
  "docs/CLI_REFERENCE.md",
55
56
  "docs/ARTIFACT_REFERENCE.md",
56
57
  "docs/TROUBLESHOOTING.md",
@@ -27,6 +27,7 @@
27
27
  "phase": { "type": "string", "minLength": 1 },
28
28
  "revision": { "type": "integer", "minimum": 0 },
29
29
  "verificationCycle": { "type": "integer", "minimum": 1 },
30
+ "workStateFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
30
31
  "contractFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
31
32
  "routeFingerprint": { "oneOf": [{ "type": "string", "pattern": "^[a-f0-9]{64}$" }, { "type": "null" }] },
32
33
  "repositoryFingerprint": { "type": "object" },