@cassiomc1/forgeloop 1.10.1 → 1.10.2

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/DOCS_INDEX.md CHANGED
@@ -32,6 +32,7 @@ integration and guide context. Use this map before editing documentation.
32
32
  | Platform adapters | [`docs/PLATFORM_ADAPTERS.md`](./docs/PLATFORM_ADAPTERS.md) | Generic CI boundary and platform mapping guidance |
33
33
  | Universal integration API | [`docs/UNIVERSAL_INTEGRATION.md`](./docs/UNIVERSAL_INTEGRATION.md) | Programmatic integration subpath, envelope semantics, and consumer map |
34
34
  | Advisory context providers | [`docs/ADVISORY_CONTEXT.md`](./docs/ADVISORY_CONTEXT.md) | Optional external host context, non-evidence trust boundary, allowlist normalization, and safety rules |
35
+ | Ripwire advisory adapter | [`docs/RIPWIRE_ADAPTER.md`](./docs/RIPWIRE_ADAPTER.md) | Ripwire-specific registration, process contract, JSON mapping, limits, and verification |
35
36
  | Local-first MCP adapter | [`docs/MCP.md`](./docs/MCP.md) | stdio default, optional strict loopback HTTP; server modes/capabilities and canonical resources |
36
37
  | Adaptive execution-profile benchmarks | [`docs/EXECUTION_PROFILE_BENCHMARKS.md`](./docs/EXECUTION_PROFILE_BENCHMARKS.md) | Measured provider/host runs, robust statistics, paired/distribution deltas, tail status, outliers, and profile-aware host context |
37
38
  | Knowledge integration gap analysis | [`docs/KNOWLEDGE_INTEGRATION_GAP_ANALYSIS.md`](./docs/KNOWLEDGE_INTEGRATION_GAP_ANALYSIS.md) | Repository-only research audit of candidate coverage, proven gaps, canonical homes, context cost, and intentional skip/defer decisions |
@@ -80,6 +81,7 @@ is historical evidence and is not part of the published core package.
80
81
  | **Fixing a broken or stale state** | [`docs/TROUBLESHOOTING.md`](./docs/TROUBLESHOOTING.md) |
81
82
  | **Looking for quick recipes** | [`docs/RECIPES.md`](./docs/RECIPES.md) |
82
83
  | **Configuring structural quality feedback** | [`docs/STRUCTURAL_QUALITY.md`](./docs/STRUCTURAL_QUALITY.md) |
84
+ | **Configuring Ripwire advisory context** | [`docs/RIPWIRE_ADAPTER.md`](./docs/RIPWIRE_ADAPTER.md) |
83
85
  | **Understanding verification trust** | [`docs/REVISION_PROVIDERS.md`](./docs/REVISION_PROVIDERS.md#differential-verification-scope) |
84
86
  | **Understanding attestation trust** | [`docs/CODE_ATTESTATION.md`](./docs/CODE_ATTESTATION.md#trust-levels) |
85
87
  | **Maintaining generated diagrams** | [`docs/diagrams/README.md`](./docs/diagrams/README.md) |
@@ -140,7 +142,7 @@ scope, exact commands, and migration boundary are recorded in
140
142
  [`scripts/CI_VALIDATORS.md`](./scripts/CI_VALIDATORS.md).
141
143
 
142
144
  The package has no runtime dependencies. Development dependencies are limited
143
- to ESLint and c8 and are checked by
145
+ to c8, ESLint, TypeScript, and YAML and are checked by
144
146
  `npm run dependency:policy`. GitHub Actions use `npm ci`, pinned action SHAs,
145
147
  CodeQL, dependency review, and generated-release notes; npm publication still
146
148
  uses trusted OIDC publishing and is not implied by local verification.
package/README.md CHANGED
@@ -142,7 +142,9 @@ ForgeLoop can consume host-provided advisory context through the Integration
142
142
  API. Providers are lazy and opt-in, and ForgeLoop does not persist their
143
143
  results. Provider output is never lifecycle state, evidence, authority,
144
144
  completion truth, or next-action authority, and it is never executable as a
145
- protocol command. See [`docs/ADVISORY_CONTEXT.md`](./docs/ADVISORY_CONTEXT.md).
145
+ protocol command. The optional Ripwire adapter follows the same boundary; see
146
+ [`docs/ADVISORY_CONTEXT.md`](./docs/ADVISORY_CONTEXT.md) and
147
+ [`docs/RIPWIRE_ADAPTER.md`](./docs/RIPWIRE_ADAPTER.md).
146
148
 
147
149
  ### Optional task boundaries and differential verification
148
150
 
@@ -505,11 +507,10 @@ JSON is size/depth limited; manifests, schemas, receipts, and secret-like
505
507
  values are checked; and install-capable verification requires trusted host
506
508
  authority. See [`THREAT_MODEL.md`](./THREAT_MODEL.md) for the full inventory.
507
509
 
508
- Development tooling is intentionally separate from runtime dependencies. The
509
- repository policy allows only ESLint and c8 as development dependencies;
510
- `npm run dependency:policy` fails if runtime or unapproved dependencies
511
- appear. The documentation renderer is vendored and pinned under
512
- `vendor/archify/v2.15.0/` rather than installed as a package dependency.
510
+ Development tooling stays separate from runtime dependencies. The policy allows
511
+ c8, ESLint, TypeScript, and YAML as development dependencies;
512
+ `npm run dependency:policy` rejects runtime or unapproved dependencies. Archify
513
+ is vendored at `vendor/archify/v2.15.0/` rather than installed as a package.
513
514
 
514
515
  To report vulnerabilities or contribute changes, see
515
516
  [`SECURITY.md`](./SECURITY.md) and [`CONTRIBUTING.md`](./CONTRIBUTING.md).
@@ -555,8 +556,8 @@ through `init`, `update`, or `doctor`.
555
556
  ## Release and maintenance
556
557
 
557
558
  The release workflow uses [npm trusted publishing](https://docs.npmjs.com/trusted-publishers)
558
- through GitHub Actions OIDC. A `vX.Y.Z` tag must match `package.json`; after
559
- publishing, verify the immutable release identity:
559
+ through GitHub Actions OIDC. A merged `vX.Y.Z` tag must match `package.json`;
560
+ after publishing, verify the immutable release identity:
560
561
 
561
562
  ```bash
562
563
  RELEASE_COMMIT="$(git rev-list -n1 vX.Y.Z)"
@@ -172,3 +172,27 @@ The public boundary reports these stable codes:
172
172
 
173
173
  The host owns whether and when to display or use advisory context. ForgeLoop
174
174
  owns only the bounded normalization and trust-role projection.
175
+
176
+ ## Ripwire adapter
177
+
178
+ ForgeLoop includes an optional host-injected adapter for the [Ripwire](https://github.com/redhat-et/ripwire)
179
+ ranked source map. The adapter is deliberately outside the default runtime:
180
+ the host must provide an absolute executable path and an exact expected
181
+ version, register the returned provider under the `ripwire` key, and invoke
182
+ `recallAdvisoryContext` explicitly. Creating the provider performs no discovery,
183
+ network access, process start, or lifecycle write.
184
+
185
+ The adapter runs Ripwire's qualified `--for=<query> --signatures-only --json
186
+ --no-cache --exclude=.forgeloop` form with `shell: false`, closes standard
187
+ input, bounds stdout to 1 MiB and stderr to 64 KiB, and applies the caller's
188
+ existing advisory deadline. It validates the version immediately before the
189
+ query, rejects malformed JSON and unsafe paths, and never copies raw stderr
190
+ into an error message. Ripwire's graph is approximate, so the first returned
191
+ item is a bounded status card that preserves cap, omission, ambiguity,
192
+ unindexed-content, and unknown-completeness warnings after core normalization.
193
+
194
+ See [RIPWIRE_ADAPTER.md](RIPWIRE_ADAPTER.md) for registration, tests, the
195
+ opt-in real-binary smoke test, and the retrieval benchmark. A real binary and
196
+ its exact version must be qualified by the host; ForgeLoop does not install or
197
+ discover Ripwire and does not treat an unavailable smoke test as proof of
198
+ interoperability.
@@ -7,7 +7,7 @@
7
7
  ForgeLoop is a portable protocol and support CLI for verifiable engineering workflows. It records and validates task state, contracts, routing, checks, evidence, continuity, and optional code attestations. It does not become an agent scheduler, delegation service, source-control authority, or secret manager.
8
8
 
9
9
  Protocol version: 1
10
- Package version: 1.10.1
10
+ Package version: 1.10.2
11
11
 
12
12
  ## Canonical loop
13
13
 
package/docs/MCP.md CHANGED
@@ -135,7 +135,7 @@ forgeloop-mcp-http --project /repo --mode safe # 127.0.0.1:3333
135
135
 
136
136
  | Component | Current contract |
137
137
  | --- | --- |
138
- | ForgeLoop core package | `>=1.5.0 <2` dependency range; current release `1.10.1` |
138
+ | ForgeLoop core package | `>=1.5.0 <2` dependency range; current release `1.10.2` |
139
139
  | ForgeLoop protocol | `1` |
140
140
  | Integration API | `1` |
141
141
  | MCP package | `0.1.x` initial package |
@@ -34,6 +34,8 @@ The published tarball includes the following consumer-facing groups:
34
34
  and generated results are repository evidence and are excluded.
35
35
  - **User documentation:** the getting-started, integration, CLI, artifact,
36
36
  troubleshooting, release, package-boundary, and related reference pages.
37
+ The advisory-context and Ripwire adapter guides ship with the corresponding
38
+ public integration surface.
37
39
  The typed diagram sources, generated HTML/SVG/receipt artifacts, and
38
40
  source-bound review records under `docs/diagrams/` are included together so
39
41
  the packaged documentation keeps its visual provenance.
@@ -51,6 +53,9 @@ The tarball intentionally omits repository-only material:
51
53
  exception);
52
54
  - raw or aggregate benchmark results, package archives, and release train
53
55
  contracts;
56
+ - the Ripwire retrieval benchmark runner, cases, and fixture corpus; those
57
+ maintainer-only files require a clean repository checkout and are not part of
58
+ the consumer adapter surface;
54
59
  - historical release plans and retired MCP adapter sources; the MCP adapter
55
60
  is published as its own package;
56
61
  - the repository README hero PNG, which is a GitHub-only asset. The packaged
@@ -11,8 +11,8 @@ preparation and verification checklist; it does not authorize publication.
11
11
  - [ ] `npm run release:identity` passes for the candidate version.
12
12
  - [ ] No release tag or registry version collision exists.
13
13
  - [ ] `npm pack --dry-run` contains the required scenario definitions but no
14
- raw or aggregate benchmark results, tests, local state, or repository
15
- metadata.
14
+ raw or aggregate benchmark results, Ripwire benchmark runner/cases/
15
+ fixtures, tests, local state, or repository metadata.
16
16
  - [ ] [`docs/PACKAGE_CONTENTS.md`](./PACKAGE_CONTENTS.md) matches the current
17
17
  `package.json` file list and documents intentional inclusions and
18
18
  exclusions.
@@ -0,0 +1,189 @@
1
+ # Ripwire advisory adapter
2
+
3
+ This document explains the optional Ripwire integration shipped with
4
+ ForgeLoop. It is an advisory context provider. It can help a host choose
5
+ which source files to inspect, but it never controls ForgeLoop state, checks,
6
+ receipts, commands, approvals, or completion.
7
+
8
+ ## When to use it
9
+
10
+ Use the adapter when a host already has a qualified Ripwire executable and
11
+ wants ranked source signatures for an explicit task query. Do not use it as a
12
+ replacement for tests, code review, lifecycle evidence, or a sound call graph.
13
+ Ripwire's resolver is approximate: same-file and same-directory edges are
14
+ useful hints, while ambiguous or unresolved edges can be missing or wrong.
15
+
16
+ ForgeLoop does not install Ripwire, search `PATH`, contact a server, create a
17
+ cache, or persist a recall. The host owns executable selection and version
18
+ qualification.
19
+
20
+ ## Registration
21
+
22
+ Import the factory from the public integration entry point and register the
23
+ returned provider under the exact `ripwire` key:
24
+
25
+ ```js
26
+ import {
27
+ createForgeLoopContext,
28
+ createRipwireAdvisoryContextProvider,
29
+ recallAdvisoryContext,
30
+ } from "@cassiomc1/forgeloop/integration";
31
+
32
+ const ripwire = createRipwireAdvisoryContextProvider({
33
+ executablePath: "/absolute/path/to/ripwire",
34
+ expectedVersion: "0.3.8",
35
+ });
36
+
37
+ const runtimeContext = createForgeLoopContext({
38
+ advisoryContextProviders: { ripwire },
39
+ });
40
+
41
+ const context = await recallAdvisoryContext({
42
+ target: "/absolute/path/to/project",
43
+ taskId: "task-123",
44
+ providerName: "ripwire",
45
+ query: "stale handoff acceptance and repository fingerprint",
46
+ limit: 6,
47
+ runtimeContext,
48
+ });
49
+ ```
50
+
51
+ `executablePath` must be absolute. `expectedVersion` is an exact version token,
52
+ not a range. Provider construction is inert. On every recall the adapter first
53
+ runs `ripwire --version`; a mismatch fails with
54
+ `E_ADVISORY_CONTEXT_PROVIDER_INVALID` before the query is attempted.
55
+
56
+ ## Process contract
57
+
58
+ The adapter invokes one command with an argv array:
59
+
60
+ ```text
61
+ <ripwire-path> <absolute-project-path> \
62
+ --for=<entire-query-string> --signatures-only --json --no-cache \
63
+ --exclude=.forgeloop
64
+ ```
65
+
66
+ The query is one argument, so shell metacharacters cannot add arguments or
67
+ commands. The child is started with `shell: false`, standard input is closed,
68
+ and stdout/stderr are read concurrently. A single deadline covers the version
69
+ probe and query. The default transport ceilings are 1 MiB for stdout and 64
70
+ KiB for stderr. On timeout or overflow the child is terminated and the error
71
+ uses a stable ForgeLoop code; raw output is not copied into the message.
72
+
73
+ The `.forgeloop` exclusion keeps lifecycle files out of the advisory source
74
+ surface. The adapter does not add other exclusion flags because every flag
75
+ must be qualified against the selected Ripwire version.
76
+
77
+ ## JSON mapping
78
+
79
+ Ripwire's `--for --json` response is expected to be an object containing a
80
+ flat `sigs` array. Each known row is mapped as follows:
81
+
82
+ | Ripwire field | ForgeLoop field | Rule |
83
+ | --- | --- | --- |
84
+ | `n` | `title` | Candidate symbol name. |
85
+ | `sig` | `summary` | Signature text, bounded before core normalization. |
86
+ | `p` + `l` | `sourceRef` | Repository-relative path and one-based line. |
87
+ | `r`, `k` | summary annotation | Rank and ranking score remain descriptive text. |
88
+ | numeric `confidence` in `[0, 1]` | `confidence` | Copied only when the upstream field is explicitly numeric and bounded. |
89
+ | `at` | omitted | A run timestamp or revision is not needed for deterministic item identity. |
90
+
91
+ PageRank, BM25, margin, and other ranking values are never converted into a
92
+ probability. Unknown fields are discarded by the core allowlist. Candidate
93
+ order is preserved, duplicates are removed by stable first occurrence, and
94
+ items stop when the requested item or total-character budget is reached.
95
+
96
+ The first item is always `Ripwire advisory status`. It states that the result
97
+ is approximate and carries bounded disclosures such as `capped`, `sigs_total`,
98
+ `sigs_shown`, `lens`, `ambiguous`, `unresolved`, `unindexed`, parse health, and
99
+ `index_completeness=unknown`. If no symbol fits, the status item says so; an
100
+ empty result never proves that the project has no impact.
101
+
102
+ Source references are rejected when they are absolute outside the project,
103
+ contain traversal segments, use an in-project symlink, or report an invalid
104
+ line. The host must still inspect the referenced file and independently verify
105
+ the proposed change.
106
+
107
+ The status item is budget-aware. When candidates or diagnostic notices do not
108
+ fit, it preserves a truthful completeness warning and says which candidate
109
+ rows or text were omitted. The final item total is checked against the same
110
+ character budget used by the core advisory normalizer.
111
+
112
+ ## Failure codes
113
+
114
+ | Situation | Code |
115
+ | --- | --- |
116
+ | Missing or unqualified executable or unsafe target | `E_ADVISORY_CONTEXT_PROVIDER_UNAVAILABLE` |
117
+ | Nonzero process exit without a qualified meaning | `E_ADVISORY_CONTEXT_RESULT_INVALID` |
118
+ | Expected version differs from `--version` output | `E_ADVISORY_CONTEXT_PROVIDER_INVALID` |
119
+ | Invalid JSON or unsupported response shape | `E_ADVISORY_CONTEXT_RESULT_INVALID` |
120
+ | Timeout | `E_ADVISORY_CONTEXT_TIMEOUT` |
121
+ | Stdout/stderr or candidate ceiling exceeded | `E_ADVISORY_CONTEXT_OUTPUT_LIMIT` |
122
+ | Unsafe content or control character in selected context | `E_PORTABLE_CONTEXT_INVALID` |
123
+
124
+ These failures affect the explicit recall operation only. They do not change a
125
+ ForgeLoop task phase and do not write `.forgeloop` state.
126
+
127
+ ## Verification
128
+
129
+ The deterministic fixture tests run without a Ripwire installation:
130
+
131
+ ```bash
132
+ node --test \
133
+ tests/ripwire-advisory-process.test.js \
134
+ tests/ripwire-advisory-normalize.test.js \
135
+ tests/ripwire-advisory-provider.test.js
136
+ ```
137
+
138
+ The real-binary smoke test is opt-in. Set both variables to a host-qualified
139
+ binary and version, then run:
140
+
141
+ ```bash
142
+ FORGELOOP_TEST_RIPWIRE_PATH=/absolute/path/to/ripwire \
143
+ FORGELOOP_TEST_RIPWIRE_VERSION=0.3.8 \
144
+ node --test tests/real-ripwire-advisory.test.js
145
+ ```
146
+
147
+ Without those variables the test is skipped and interoperability remains
148
+ `NOT_VERIFIED`. When it runs, it requires a candidate reference to the known
149
+ fixture source and compares the complete fixture tree before and after recall,
150
+ so a binary that mutates the project fails the test. The test does not install
151
+ software or discover a binary.
152
+
153
+ ## Retrieval benchmark
154
+
155
+ The retrieval benchmark is a repository-maintainer check. Its runner, cases,
156
+ and fixture corpus are intentionally excluded from the core npm tarball; the
157
+ published consumer surface is the adapter, its declarations, and this guide.
158
+ Run it from a clean ForgeLoop checkout when a host-qualified Ripwire binary is
159
+ available.
160
+
161
+ `benchmarks/ripwire-context/cases.json` freezes six task-shaped queries,
162
+ expected files, lexical baseline terms, and the ForgeLoop commit used for the
163
+ comparison. Run the benchmark only against a clean checkout and an explicitly
164
+ qualified binary:
165
+
166
+ ```bash
167
+ node scripts/benchmark-ripwire-context.mjs \
168
+ --project /absolute/path/to/forgeloop \
169
+ --ripwire-path /absolute/path/to/ripwire \
170
+ --version 0.3.8 \
171
+ --cases benchmarks/ripwire-context/cases.json \
172
+ --runs 5 \
173
+ --json
174
+ ```
175
+
176
+ The report includes per-case and per-run expected-file coverage, misses,
177
+ irrelevant references, baseline bytes, normalized adapter bytes, transport
178
+ bytes when observed, and median/min/max durations. A file seen in only one
179
+ repetition is reported as observed across runs but does not count as a
180
+ consistently found file. A missing binary, version, dirty checkout, or commit
181
+ mismatch produces `NOT_VERIFIED`; it is never reported as a performance win.
182
+
183
+ ## Scope boundary
184
+
185
+ The adapter is intentionally limited to source-map retrieval. It does not
186
+ implement Ripwire's body packing, impact commands, cache management, server
187
+ mode, automatic file reads, lifecycle transitions, evidence production, or
188
+ publication. Those features require a separate contract and separate
189
+ qualification work.
@@ -39,6 +39,15 @@ dark presentation so it remains legible in repository previews; the adjacent tex
39
39
  [`README.md`](../../README.md#architecture-flow) carries the same lifecycle
40
40
  semantics for text-only readers.
41
41
 
42
+ Advisory context, including the optional Ripwire adapter, is intentionally not
43
+ drawn as a lifecycle node or transition. It is a host-injected, explicit,
44
+ non-evidence input that can guide inspection while remaining outside state,
45
+ authority, verification, completion, and next-action decisions. Its boundary
46
+ is documented in [`ADVISORY_CONTEXT.md`](../ADVISORY_CONTEXT.md) and
47
+ [`RIPWIRE_ADAPTER.md`](../RIPWIRE_ADAPTER.md); keeping it out of these P0
48
+ visuals prevents an optional side channel from being mistaken for protocol
49
+ control flow.
50
+
42
51
  Archify is vendored at `vendor/archify/v2.15.0/archify` under its MIT license.
43
52
  The exact source commit and cryptographic vendor-tree hash are recorded in
44
53
  `vendor/archify/v2.15.0/PIN.json`; generated-file hashes are recorded in the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cassiomc1/forgeloop",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "Portable, verifiable engineering protocol for AI coding environments and developer workflows",
5
5
  "repository": {
6
6
  "type": "git",
@@ -52,6 +52,7 @@
52
52
  "docs/GETTING_STARTED.md",
53
53
  "docs/CROSS_HARNESS_CONTINUITY.md",
54
54
  "docs/ADVISORY_CONTEXT.md",
55
+ "docs/RIPWIRE_ADAPTER.md",
55
56
  "docs/CLI_REFERENCE.md",
56
57
  "docs/ARTIFACT_REFERENCE.md",
57
58
  "docs/TROUBLESHOOTING.md",