@n8r/surface 0.1.0-experimental.2 → 0.1.0-experimental.5

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 (118) hide show
  1. package/README.md +30 -4
  2. package/dist/cli.js +174 -22
  3. package/dist/codec.d.ts +2 -0
  4. package/dist/codec.js +22 -7
  5. package/dist/codex.d.ts +1 -1
  6. package/dist/codex.js +26 -10
  7. package/dist/contracts.d.ts +108 -2
  8. package/dist/cyclonedx-schemas/bom-1.7.schema.json +6700 -0
  9. package/dist/cyclonedx-schemas/cryptography-defs.schema.json +576 -0
  10. package/dist/cyclonedx-schemas/jsf-0.82.schema.json +240 -0
  11. package/dist/cyclonedx-schemas/spdx.schema.json +786 -0
  12. package/dist/cyclonedx-validation.d.ts +1 -0
  13. package/dist/cyclonedx-validation.js +45 -0
  14. package/dist/html.js +27 -3
  15. package/dist/recent.d.ts +9 -0
  16. package/dist/recent.js +71 -0
  17. package/dist/revisions.js +42 -0
  18. package/dist/skill-artifacts-cli.d.ts +1 -0
  19. package/dist/skill-artifacts-cli.js +13 -0
  20. package/dist/skill-artifacts.d.ts +15 -0
  21. package/dist/skill-artifacts.js +184 -0
  22. package/dist/skill-cyclonedx.d.ts +26 -0
  23. package/dist/skill-cyclonedx.js +214 -0
  24. package/dist/skill-presentation.d.ts +10 -0
  25. package/dist/skill-presentation.js +108 -0
  26. package/dist/skill-surface-cli.d.ts +1 -0
  27. package/dist/skill-surface-cli.js +37 -0
  28. package/dist/skill-surface-store.d.ts +7 -0
  29. package/dist/skill-surface-store.js +126 -0
  30. package/dist/surface-bom.d.ts +73 -0
  31. package/dist/surface-bom.js +139 -0
  32. package/dist/surface-draft.d.ts +6 -3
  33. package/dist/surface-draft.js +20 -3
  34. package/dist/surface-instructions.d.ts +2 -1
  35. package/dist/surface-instructions.js +10 -1
  36. package/dist/surface-overview.d.ts +15 -0
  37. package/dist/surface-overview.js +86 -0
  38. package/dist/surface-store.d.ts +5 -7
  39. package/dist/surface-store.js +34 -2
  40. package/dist/surface-view.d.ts +3 -0
  41. package/dist/surface-view.js +50 -0
  42. package/dist/validate.js +298 -0
  43. package/docs/n8r-surface/cli-bundles.md +72 -0
  44. package/docs/n8r-surface/command-outcomes.md +151 -4
  45. package/docs/n8r-surface/contracts.md +10 -0
  46. package/docs/n8r-surface/critical-path.md +21 -0
  47. package/docs/n8r-surface/first-use-access.md +143 -0
  48. package/docs/n8r-surface/first-use-overview.md +262 -0
  49. package/docs/n8r-surface/getting-started.md +55 -88
  50. package/docs/n8r-surface/guided-journey-verification.md +137 -0
  51. package/docs/n8r-surface/implementation-decisions.md +14 -14
  52. package/docs/n8r-surface/instance-first-research.md +209 -0
  53. package/docs/n8r-surface/npm-distribution.md +39 -69
  54. package/docs/n8r-surface/npm-release.md +141 -14
  55. package/docs/n8r-surface/product-direction.md +327 -0
  56. package/docs/n8r-surface/researcher-skill.md +105 -51
  57. package/docs/n8r-surface/security-assurance-strategy.md +267 -0
  58. package/docs/n8r-surface/skill-bom-verification.md +142 -0
  59. package/docs/n8r-surface/skill-cyclonedx-verification.md +144 -0
  60. package/docs/n8r-surface/skill-cyclonedx.md +85 -0
  61. package/docs/n8r-surface/skill-manual.md +129 -0
  62. package/docs/n8r-surface/skill-surface-artifacts.md +234 -0
  63. package/docs/n8r-surface/skill-usefulness-verification.md +135 -0
  64. package/docs/n8r-surface/skill-workspace-automation.md +359 -0
  65. package/docs/n8r-surface/surface-description-contract.md +224 -0
  66. package/docs/n8r-surface/surface-descriptions.md +173 -0
  67. package/docs/n8r-surface/surface-relationships.md +231 -0
  68. package/docs/n8r-surface/tester-candidate.md +158 -0
  69. package/docs/n8r-surface/versioning.md +55 -66
  70. package/docs/n8r-surface/workspace-human-check.md +101 -0
  71. package/docs/n8r-surface/workspace-installation.md +68 -0
  72. package/docs/n8r-surface/workspace-verification.md +350 -0
  73. package/docs/n8r-surface/workspace.md +83 -0
  74. package/examples/researcher/README.md +8 -0
  75. package/examples/researcher/cyclonedx/configured/README.md +7 -0
  76. package/examples/researcher/cyclonedx/configured/manifest.json +10 -0
  77. package/examples/researcher/cyclonedx/configured/mapping.json +323 -0
  78. package/examples/researcher/cyclonedx/configured/surface-records.json +1275 -0
  79. package/examples/researcher/cyclonedx/configured/surface.cdx.json +79 -0
  80. package/examples/researcher/descriptions/README.md +29 -0
  81. package/examples/researcher/descriptions/bound-r1.json +141 -0
  82. package/examples/researcher/descriptions/bound-r2.json +153 -0
  83. package/examples/researcher/descriptions/capability.json +167 -0
  84. package/examples/researcher/descriptions/research-r1.json +153 -0
  85. package/examples/researcher/descriptions/research-r2.json +157 -0
  86. package/examples/researcher/descriptions/sources.md +24 -0
  87. package/examples/researcher/relationships/README.md +34 -0
  88. package/examples/researcher/relationships/bound-r1.json +346 -0
  89. package/examples/researcher/relationships/bound-r2.json +358 -0
  90. package/examples/researcher/relationships/capability.json +325 -0
  91. package/examples/researcher/relationships/config/assistant.env.example +4 -0
  92. package/examples/researcher/relationships/research-r1.json +300 -0
  93. package/examples/researcher/relationships/research-r2.json +304 -0
  94. package/examples/researcher/relationships/sources.md +38 -0
  95. package/examples/researcher/surface-bom/README.md +17 -0
  96. package/examples/researcher/surface-bom/initial.cdx.json +188 -0
  97. package/package.json +1 -1
  98. package/plugins/n8r-surface/.codex-plugin/plugin.json +2 -2
  99. package/plugins/n8r-surface/LICENSING.md +3 -0
  100. package/plugins/n8r-surface/plugin.json +2 -2
  101. package/plugins/n8r-surface/skills/research/SKILL.md +79 -38
  102. package/plugins/n8r-surface/skills/research/references/artifacts.md +152 -0
  103. package/plugins/n8r-surface/skills/research/references/cyclonedx.md +207 -0
  104. package/plugins/n8r-surface/skills/research/references/discovery-map.md +20 -2
  105. package/plugins/n8r-surface/skills/research/references/examples/bound-r1.json +346 -0
  106. package/plugins/n8r-surface/skills/research/references/examples/capability.json +325 -0
  107. package/plugins/n8r-surface/skills/research/references/examples/research-r1.json +300 -0
  108. package/plugins/n8r-surface/skills/research/references/examples/surface.cdx.json +188 -0
  109. package/plugins/n8r-surface/skills/research/references/first-use-access.md +97 -0
  110. package/plugins/n8r-surface/skills/research/references/first-use-overview.md +101 -0
  111. package/plugins/n8r-surface/skills/research/references/instance-first.md +125 -0
  112. package/plugins/n8r-surface/skills/research/references/working-notes.md +6 -1
  113. package/plugins/n8r-surface/skills/research/references/workspace.md +89 -0
  114. package/plugins/n8r-surface/skills/research/scripts/THIRD-PARTY-NOTICES.txt +273 -0
  115. package/plugins/n8r-surface/skills/research/scripts/artifacts.mjs +8348 -0
  116. package/plugins/n8r-surface/skills/research/scripts/cyclonedx.mjs +28113 -0
  117. package/plugins/n8r-surface/skills/research/scripts/surface.mjs +27800 -0
  118. package/plugins/n8r-surface/skills/research/scripts/workspace.mjs +120 -0
@@ -0,0 +1,359 @@
1
+ # Installed Researcher workspace acceptance
2
+
3
+ Issue [#43](https://github.com/injectionator/n8r-surface/issues/43) binds only the
4
+ first three [canonical scenarios](../../tests/acceptance/skill-workspace.feature)
5
+ to Cucumber: create, repeat setup and fresh-session reopen. The other scenarios
6
+ remain manual. Ordinary `npm test` is offline and never starts inference.
7
+
8
+ ## Scope and interface
9
+
10
+ The runner uses **Codex CLI 0.166.0 app-server over stdio**, not the desktop UI
11
+ and not the standalone n8r command. It requires an enabled installed Researcher
12
+ **0.1.9**, byte-identical to source commit
13
+ `3cb08f59a4a932121bdd1c742fbac724d12a6d74`. The default installation is the normal
14
+ Codex plugin cache. `--installed PATH --revision FULL_COMMIT` can select another
15
+ already-installed, byte-verified 0.1.9 candidate. The runner never installs or
16
+ replaces a plugin. See the [installation procedure](workspace-installation.md).
17
+
18
+ The [documented skill input](https://developers.openai.com/codex/app-server#skills)
19
+ loads the discovered installed SKILL.md. The harness supplies only the selected
20
+ folder and scenario request. The model reads the skill reference and chooses the
21
+ installed helper invocation; the harness never invokes the helper or writes
22
+ workspace identity metadata. Its sole content write is the synthetic user note
23
+ between create and repeat.
24
+
25
+ One ephemeral thread holds create and repeat. Reopen starts another app-server
26
+ process and empty ephemeral thread, with no copied transcript, expected identity
27
+ or answer. The first process is closed; the second must fail to read the old
28
+ thread through `thread/read`. The
29
+ [permission profile](https://learn.chatgpt.com/docs/permissions) grants writes only
30
+ to the disposable workspace and reads to the installed plugin and runtime paths.
31
+ It denies access to retained evidence; a sandbox command checks allowed skill
32
+ reads and denied evidence reads before each session, including the actual setup
33
+ receipt before reopen. This technical probe never invokes the workspace helper.
34
+
35
+ Memories, project instructions, apps, configured MCP servers, browser/computer
36
+ access, remote control, multi-agent/history features and web search are disabled.
37
+ The normal sign-in is used by the host, never copied into fixtures or receipts.
38
+ Local commands receive a restricted environment. Command network access is off;
39
+ Codex authentication and model service traffic still need network access.
40
+
41
+ These controls establish the tested CLI boundary, not a general sandbox security
42
+ certification. Runtime paths remain readable. The Codex service processes the
43
+ conversation. No claim is made about desktop behavior, other hosts, or complete
44
+ system-wide file auditing.
45
+
46
+ ## Run the three scenarios
47
+
48
+ Maintainer prerequisites: Node.js 22, 24 or 26; Git; `npm ci`; Codex CLI 0.166.0
49
+ signed in with ChatGPT; the identified plugin installed/enabled; a configured
50
+ available OpenAI model. The runner records the selected model and refuses a
51
+ provider fallback. A live run consumes account inference allowance and may incur
52
+ cost under the account's terms. It is opt-in and is not scheduled in CI.
53
+
54
+ From the repository root, on the branch under test:
55
+
56
+ ```sh
57
+ npm run acceptance:skill -- --live --evidence .local/skill-acceptance/run-1
58
+ ```
59
+
60
+ The evidence directory must not already exist. Create its parent first if needed:
61
+ `mkdir -p .local/skill-acceptance`. Keep it private and ignored. A second run uses
62
+ a new evidence directory and automatically creates a new disposable workspace:
63
+
64
+ ```sh
65
+ npm run acceptance:skill -- --live --evidence .local/skill-acceptance/run-2
66
+ ```
67
+
68
+ There are at most three user turns, one per scenario, each limited to 120 seconds,
69
+ and a 600-second suite limit. No simulated user, retries or automatic conversation
70
+ repair are used. A missing capability, unexpected host question or unanswered
71
+ setup question is a failure/blocker; dependent scenarios cannot pass.
72
+
73
+ The runner reports **automated** results separately from full Gherkin acceptance.
74
+ Independent checks compare the saved format, UUID, folder-derived name, supplied
75
+ purpose, complete entry lists, hashes and file timestamps. They compare helper
76
+ receipts and assistant identity/location claims with filesystem readback. This
77
+ detects changed-note and wrong-identity evidence without a model grader.
78
+
79
+ Semantic criteria, such as useful continuation, accurate attachment claims and
80
+ absence of unnecessary questions, remain **pending human review**. Each scenario
81
+ runs its automated checks before an After hook marks it pending. Cucumber's
82
+ passing intermediate steps are not full scenario acceptance. No pending criterion
83
+ is counted as passed by default.
84
+
85
+ Exit codes:
86
+
87
+ - **1:** at least one automated scenario or final installation check failed.
88
+ - **2:** blocked prerequisites, or automated checks passed but human review is
89
+ pending. Inspect `results.json` and `blocked.json` to distinguish these cases.
90
+ - **0:** successful owned-fixture cleanup. Offline report and review modes have
91
+ their own exit meanings below. A live run does not claim full human
92
+ acceptance and therefore does not return 0 in this increment.
93
+
94
+ ## Evidence and human verification
95
+
96
+ The evidence directory contains run/install identity once (`metadata.json`), raw
97
+ app-server requests/events, each turn, before/after inventories, final metadata,
98
+ Cucumber JSON and individual results with outstanding review criteria. Failed
99
+ attempts get their own directory; rerunning never overwrites them. Paths, model
100
+ responses and tool receipts are private: do not commit these files or paste raw
101
+ receipts into public issues/PRs. Review and sanitize any published summary.
102
+
103
+ Tester steps, after the maintainer has prepared the prerequisites above:
104
+
105
+ - [ ] Run the first command from the repository root. Expect three automated
106
+ results and exit 2 when all automated checks pass with human review pending.
107
+ An automated failure, skipped prerequisite or `blocked.json` is not a pass.
108
+ - [ ] Open `results.json`, `1-turn.json`, `2-turn.json` and `3-turn.json` in the
109
+ selected private evidence directory. For each result, inspect the listed
110
+ `reviewRequired` criteria against actual responses and tool activity.
111
+ Expect creation only, recognition on repeat, and useful readiness orientation
112
+ on reopen. No research, credentials request, attachment claim or repeated
113
+ setup permission question should occur. Use the
114
+ [existing experience rubric](workspace-human-check.md#independent-evidence-and-report).
115
+ - [ ] Open the inventory files and `final-record.json`. Expect only identity
116
+ metadata after create, then that metadata plus the synthetic note, unchanged
117
+ through repeat/reopen. Inspect `setup.jsonl` and `reopen.jsonl` for the installed
118
+ helper path, denied-evidence probes and distinct empty ephemeral sessions.
119
+ - [ ] Run again with `run-2`. Expect the same observable outcomes with a different
120
+ disposable destination, UUID, session IDs and timings. These values may vary;
121
+ preservation within one journey must not vary.
122
+ - [ ] Report **Pass / Fail / Blocked** per scenario, including the reviewed run
123
+ directory and criterion, without publishing private transcripts. An automated
124
+ pass with unreviewed criteria is **Pending**, not human acceptance.
125
+
126
+ After preserving/reviewing evidence, clean only the owned disposable fixture:
127
+
128
+ ```sh
129
+ npm run acceptance:skill -- --cleanup --evidence .local/skill-acceptance/run-1
130
+ ```
131
+
132
+ Expected: exit 0 and “Removed owned fixture only; evidence retained.” Cleanup
133
+ requires the recorded ownership token and final inventory, refuses other roots,
134
+ and leaves the evidence, normal installation and earlier trials untouched.
135
+
136
+ ## Offline checker tests
137
+
138
+ ```sh
139
+ node --test tests/skill-acceptance.test.mjs
140
+ ```
141
+
142
+ These tests deliberately substitute an incorrect identity, alter a synthetic note
143
+ and timestamp, add a file, remove/fail the installed helper receipt, and fail a
144
+ scenario prerequisite. They validate the assertions; they are not installed-skill
145
+ acceptance runs. They also run in the normal offline `npm test` suite.
146
+
147
+ ## Development evidence — 8 November 2026
148
+
149
+ Initial live rehearsals used macOS, Node 26.13.0, Codex CLI 0.166.0 and the
150
+ configured `gpt-6-astra` model (medium effort). The normal installed Researcher
151
+ 0.1.9 matched all 14 files at the pinned revision before use. No installation
152
+ replacement, desktop claim, merge or release was involved.
153
+
154
+ Failed attempts are retained privately:
155
+
156
+ | Attempt | Observed result |
157
+ | --- | --- |
158
+ | Initial interface probe | Installed skill selected its helper; Node could not read its system OpenSSL configuration. Destination remained empty. |
159
+ | Permission probe launch | Nested config was incorrectly serialized as JSON rather than TOML; server did not start. |
160
+ | First runner preflight | The harness incorrectly rejected the standard configured endpoint; no inference. An offline regression test now covers it. |
161
+ | First full journey | Create passed. Repeat preserved files/identity but the checker wrongly demanded the absolute path again rather than allowing “selected folder.” Reopen was blocked by that failed prerequisite. The corrected assertion retains the create location requirement. |
162
+
163
+ Two later fresh-fixture journeys passed all three automated scenarios:
164
+
165
+ | Private run label | Create | Repeat | Fresh reopen | Full Gherkin result |
166
+ | --- | --- | --- | --- | --- |
167
+ | run-3 | 17.842 s | 11.881 s | 16.574 s | Pending human review |
168
+ | run-4 | 21.449 s | 12.872 s | 18.257 s | Pending human review |
169
+
170
+ These are developing-agent rehearsals, not PM acceptance. They used a dirty
171
+ checkout during implementation; run-4 records complete harness file digests.
172
+ A subsequent startup-deadline fix has an offline regression test; the committed
173
+ rehearsals below include that fix. The maintained feature text is
174
+ unchanged apart from selection tags. Checker tests demonstrate rejection of
175
+ incorrect identity, altered notes, ambiguous isolation failures, malformed output
176
+ and unsafe cleanup. The runner leaves human criteria pending instead of treating
177
+ these tests or filesystem results as full conversational acceptance.
178
+
179
+ ### Committed-code repetitions
180
+
181
+ Both runs below exercised clean commit
182
+ `d9c99c4e9853ca407264f126a9dd2aa6b8599df4`, with identical harness digests and
183
+ the environment/installed revision above. Each used a fresh disposable fixture,
184
+ a different generated identity, and separate setup/reopen processes. Both exited
185
+ 2 with all automated checks passed and all full scenarios pending human review.
186
+
187
+ | Private run label | Create | Repeat | Fresh reopen |
188
+ | --- | --- | --- | --- |
189
+ | run-5 | 18.251 s | 8.713 s | 17.801 s |
190
+ | run-6 | 17.966 s | 8.431 s | 14.814 s |
191
+
192
+ Independent readback confirmed unchanged repeat/reopen inventories, global
193
+ settings fingerprints and installed bytes. Both reopen receipts retain the exact
194
+ missing-thread error and denied evidence reads. Agent inspection of the messages
195
+ found orientation, no repeated initialization question, honest attachment/access
196
+ boundaries and no research activity. This is an agent assessment, not PM acceptance;
197
+ the runner correctly leaves those human criteria pending. The documented cleanup
198
+ command then removed both owned fixtures, exited 0 and retained all evidence.
199
+
200
+ A deliberately missing installation exited 2 before inference and marked all
201
+ three scenarios blocked. All 153 offline tests passed, including 14 acceptance
202
+ checker/adapter tests. The package check passed locally on Node 26.13.0. CI for
203
+ `d9c99c4` passed Node 22/24/26, fixtures/tooling, Markdown and local links. Local
204
+ Markdown lint, lychee 0.24.2 offline links/anchors, citation validation and diff
205
+ checks also passed. No live inference was run by CI.
206
+
207
+ ### Human acceptance — 8 November 2026
208
+
209
+ The user ran the documented command from clean commit
210
+ `77b1bc49108c2741e012cf1d6b5ca43e3cee97ab` on macOS with Node 22.23.2,
211
+ Codex CLI 0.166.0 and `gpt-6-astra`. The installed Researcher remained 0.1.9
212
+ at the pinned revision above. All three automated scenarios passed.
213
+
214
+ After reviewing the actual final responses and relevant tool activity presented
215
+ from that run, the user explicitly accepted **create, repeat setup and
216
+ fresh-session reopen: Pass**. The user also accepted the reopen turn's denied
217
+ attempt to read the unrelated Superpowers skill; its read returned exit 1 and
218
+ the Researcher inspection subsequently succeeded. Recorded metadata/note
219
+ inventories and global-settings fingerprints were unchanged through the
220
+ applicable checks. Scenario durations were 16.998, 10.737 and 19.492 seconds.
221
+
222
+ This is human acceptance of the reviewed run, separate from the earlier agent
223
+ rehearsals. A private acceptance receipt accompanies the original run evidence;
224
+ the raw Cucumber pending results remain unchanged as the historical automated
225
+ output. Future runs still require their own human review. The user authorized
226
+ PR #44 to become ready for review, not merge or release.
227
+
228
+ ## Readable reports and recorded human verdicts
229
+
230
+ The follow-up in [#45](https://github.com/injectionator/n8r-surface/issues/45)
231
+ adds a private `review.md` after live-run finalization. It contains each actual
232
+ final response, user input, commentary, tool commands and results, including
233
+ failed or denied operations. Successful tool outputs and technical session
234
+ receipts are expandable in Markdown viewers supporting HTML details; their full
235
+ text remains in the file. Failed outputs remain visible. Missing evidence is
236
+ explicit. No model generates the report or judges the interaction.
237
+
238
+ The runner prints the report path and a SHA-256 **run fingerprint**. The companion
239
+ `review-manifest.json` binds the evidence file names/bytes and the report bytes.
240
+ These files contain private machine paths and transcripts: retain them with the
241
+ ignored run directory, not in public commits. Existing reports are verified,
242
+ never silently regenerated over different evidence.
243
+
244
+ To generate or verify a report for a retained run without inference:
245
+
246
+ ```sh
247
+ npm run acceptance:skill -- --report --evidence .local/skill-acceptance/run-1
248
+ ```
249
+
250
+ Expected: exit 0 when the report is successfully generated or verified, with the
251
+ report path, fingerprint and automated status. Exit 0 here means reporting worked,
252
+ not that the scenario passed. A blocked run can have a valid readable report.
253
+ Missing required evidence prevents an overall Pass. Once a verdict receipt exists,
254
+ this command also shows the three human verdicts and combined overall status.
255
+
256
+ ### Human review task list
257
+
258
+ Prerequisite: a completed run from the command above or the live command. No new
259
+ Codex sign-in, network access or inference is needed for report/review commands.
260
+ From the repository root:
261
+
262
+ - [ ] Run `--report` as shown above and open the printed `review.md` path. Read
263
+ each scenario's human criteria, actual final response and tool activity.
264
+ Inspect any failed commands and preservation warnings. Expect the same actual
265
+ responses as the retained turn receipts; there are no invented summaries.
266
+ - [ ] Copy the report's run fingerprint. Choose **Pass**, **Fail** or **Blocked**
267
+ independently for create, repeat and reopen. The command below shows all Pass
268
+ only as an example; replace each verdict with your actual judgment, replace
269
+ the fingerprint and reviewer, and use the optional comment for any caveats:
270
+
271
+ ```sh
272
+ npm run acceptance:skill -- --review \
273
+ --evidence .local/skill-acceptance/run-1 \
274
+ --run COPY_THE_64_CHARACTER_RUN_FINGERPRINT \
275
+ --reviewer 'Your name' \
276
+ --create Pass --repeat Pass --reopen Pass \
277
+ --comment 'Reviewed the actual responses and tool activity.'
278
+ ```
279
+
280
+ Expect a separate `human-review.json` containing the run fingerprint, report
281
+ digest, reviewer, date/time, each verdict and comment. The terminal shows
282
+ automated status, human verdicts and overall status together. **Pass → exit 0;
283
+ Fail → exit 1; Blocked → exit 2.** A human Pass cannot override an automated
284
+ failure, final preservation error, missing evidence or blocked prerequisite.
285
+ - [ ] Run `--report` again. Expect verification of the unchanged evidence/report
286
+ and the recorded human verdicts. Original Cucumber JSON and pending results
287
+ remain untouched; a verdict receipt does not retroactively alter execution.
288
+ - [ ] Report **Pass / Fail / Blocked** for this review workflow with the private
289
+ run reference and any failed step. If commands refuse modified evidence, an
290
+ incorrect fingerprint or a duplicate review, that is the expected protection;
291
+ retain the refusal when reporting a problem. Do not publish raw private files.
292
+
293
+ Only one review receipt is supported per run in this increment. Duplicate
294
+ submissions refuse to overwrite it. A correction workflow, reviewer identity
295
+ verification and signed audit records are out of scope. A reviewer name is a
296
+ self-attribution, not authentication. Fingerprints detect drift relative to the
297
+ retained manifest; they do not make files tamper-proof against someone able to
298
+ rewrite both evidence and manifest. Evidence must be quiescent while reporting
299
+ and reviewing; concurrent writers are unsupported.
300
+
301
+ Owned-fixture cleanup still uses `--cleanup`. It retains reports and verdicts;
302
+ its later `cleanup.json` receipt is excluded from the evidence fingerprint. The
303
+ three generated review files are also excluded from that fingerprint, with
304
+ report bytes bound separately. All other evidence files are included. Symlinks,
305
+ nested entries and files over 64 MiB are refused. Historical manually written
306
+ acceptance receipts are preserved, not automatically imported as new approval.
307
+
308
+ Offline report/review checks:
309
+
310
+ ```sh
311
+ node --test tests/skill-review.test.mjs
312
+ ```
313
+
314
+ These tests use synthetic reviewer names and verdicts. They do not establish
315
+ human acceptance of any real run. Live execution retains its existing pending
316
+ exit behavior; `--review` is the separate acceptance step.
317
+
318
+ ### Report/review development evidence — 8 November 2026
319
+
320
+ The observed baseline was the user's accepted #43 run: an agent had to extract
321
+ responses/tools from JSON for human review. The new offline report command was
322
+ exercised against that retained real run and a retained missing-installation run;
323
+ they reported automated Pass and Blocked respectively without new inference or
324
+ rewriting raw evidence. The earlier manual acceptance receipt was preserved and
325
+ was not imported as a new command-recorded review.
326
+
327
+ A fresh installed-skill run on macOS, Node 26.13.0, Codex CLI 0.166.0 and the
328
+ configured `gpt-6-astra` model passed all three automated scenarios and generated
329
+ the report automatically. The installed 0.1.9 plugin matched the same pinned
330
+ revision before and after. This was a development checkout with harness file
331
+ hashes retained privately, not a clean-commit or human acceptance claim.
332
+
333
+ The agent checked every final response and command against the readable report,
334
+ then exercised the documented review command using reviewer name
335
+ “Codex agent rehearsal (not human acceptance)” and an explicit rehearsal comment.
336
+ It recorded three Pass verdicts, exited 0 and displayed separate automated/human
337
+ results. Offline report verification still succeeded after owned-fixture cleanup;
338
+ raw results and all evidence remained retained. These verdicts test the recording
339
+ workflow; they are not the user's acceptance of this increment.
340
+
341
+ Focused offline checks cover changed/missing evidence, wrong fingerprints,
342
+ modified reports, invalid/duplicate reviews, blocked/failing aggregation, null or
343
+ empty required evidence, and interrupted-turn tool recovery from session receipts.
344
+ The latter two cases were found in fresh review, corrected and regression-tested.
345
+ All 171 offline tests passed, including 18 report/review cases; the installed
346
+ package check also passed on Node 26.13.0. No new dependencies or live CI were added.
347
+
348
+ A second fresh run exercised clean commit `1eb4cae` with the same environment
349
+ and installed skill. All three automated scenarios passed in 52.7 seconds;
350
+ live execution retained its pending-human status. The agent inspected the actual
351
+ responses, tool activity, preservation and isolation receipts, then recorded an
352
+ explicitly labeled agent rehearsal with three Pass verdicts (exit 0). Cleanup
353
+ and offline report verification both exited 0, preserving the exact fingerprint
354
+ and recorded verdicts. This does not establish desktop or human acceptance.
355
+
356
+ A later offline regression caught an evidence file named `__proto__` being omitted
357
+ from a plain JavaScript object's hash map. Null-prototype maps now include that
358
+ filename; changing its contents is detected. The final narrow fix was verified
359
+ by the offline suite rather than another live inference run.
@@ -0,0 +1,224 @@
1
+ # Capability and Bound Surface contract 0.2
2
+
3
+ This bounded library contract implements [#50](https://github.com/injectionator/n8r-surface/issues/50)
4
+ within the one AI Surface Model. It supports the [agreed delivery intent](surface-descriptions.md),
5
+ not a universal schema or a released Researcher workflow. The standalone skill
6
+ must not call or depend on the `n8r-surface` CLI. Skill artifact production is #51;
7
+ installed-workflow and human acceptance are #52. Observed Surface remains deferred.
8
+
9
+ For the revised #50 verification, start with [shared relationships 0.3](surface-relationships.md).
10
+ This earlier bounded profile and its fixtures remain readable without alteration;
11
+ `0.3` adds consistent node/edge metadata across both descriptions.
12
+
13
+ ## Versions and shared representation
14
+
15
+ `n8r.surface/0.2` requires `kind: "capability"` or `kind: "bound"`. It neither
16
+ reinterprets nor replaces `n8r.surface/0.1` selected definitions. Older readers
17
+ reject it. Do not change the version string to downgrade: doing so loses possible
18
+ versus configured meaning, exclusive alternatives, conflicts and instance identity.
19
+ There is no automatic conversion. Keep the original when making a separately
20
+ reviewed projection. Package versions and artifact contract versions are distinct.
21
+
22
+ Reuse the [0.1 envelope, research records and logical digests](contracts.md).
23
+ All fields below are required; empty arrays are permitted except where specified.
24
+ Objects are closed. This profile requires an empty `extensions` object and has
25
+ no arbitrary attributes or actual-setting fields. JSON is the only encoding;
26
+ `encode` and `decode` reject YAML for these descriptions. Research records retain
27
+ their existing JSON/YAML/HTML support. No new renderer is introduced here.
28
+
29
+ | Shared field | Meaning |
30
+ | --- | --- |
31
+ | `id`, `title`, `scope`, `revision`, `extensions` | Existing envelope; `extensions` must be `{}`. |
32
+ | `records` | Exact research `{id, revision, digest}` references. |
33
+ | `vocabularies` | Unique `{id, version}` entries; terms remain vocabulary-specific. |
34
+ | `nodes` | `{id, label, type: {vocabulary, term}}`; useful component/target identity only. |
35
+ | `coverage`, `gaps` | Explicit coverage limits, missing information and next research needs. |
36
+
37
+ A basis entry is `{record, revision, items}`. `items` is nonempty and unique,
38
+ referring to findings, or to decisions only in the dedicated `decisions` field.
39
+ Referenced research revisions must occur in `records`. Source identity, version,
40
+ date, locator, coverage and limitations live in the research record, not copied
41
+ raw configuration. All IDs are opaque, stable and case-sensitive. Labels are not
42
+ identity matching rules. An omitted node/edge/binding is unspecified, not absent.
43
+
44
+ ## Capability Surface
45
+
46
+ `kind: "capability"` adds `capabilities` and `exclusiveGroups`.
47
+
48
+ Each capability is `{id, from, to, type, state, basis, conditions, note}`. Endpoints
49
+ resolve to local nodes and type vocabulary resolves locally. Shared components,
50
+ parallel edges, cycles and self-loops are allowed. Each edge is a possible
51
+ relationship, never a selected composition. `conditions` lists material conditions
52
+ and `note` explains applicability and uncertainty. Empty conditions do not prove
53
+ unconditional support outside the stated scope.
54
+
55
+ | State | Evidence check |
56
+ | --- | --- |
57
+ | `possible` | Nonempty basis; all cited findings are `known`, subject equals `from`, property is `supports`, and every claim value equals the `to` node ID. |
58
+ | `absent` | Nonempty basis; all findings are `absent` with the same subject/property/target rule. This is scoped absence of support, not an unbound instance. |
59
+ | `conflicting` | Nonempty basis containing a conflicting finding; subject/property still match. Inspect all competing values in research. No target is selected. |
60
+ | `unknown`, `omitted`, `redacted`, `out-of-scope` | No support assertion. Any basis resolves to findings about that subject/property; notes explain the state. |
61
+
62
+ Each exclusive group is `{id, members}` with at least two distinct capability
63
+ IDs. It means **at most one** member may be configured in this bounded instance.
64
+ It does not require a selection, claim exhaustive alternatives, or resolve a
65
+ conflict. The synthetic authentication group is a fixture constraint, not a general
66
+ claim that every product makes OIDC and SAML mutually exclusive. Conditions and
67
+ other constraints remain human-readable; the checker does not execute them.
68
+
69
+ ## Bound Surface
70
+
71
+ `kind: "bound"` adds `capability`, `instance` and `bindings`:
72
+
73
+ - `capability` pins one Capability Surface `{id, revision, digest}`.
74
+ - `instance` is `{id, label}` with an opaque identity distinct from the capability
75
+ artifact and its components. It contains no location or credentials.
76
+ - Each binding is `{id, capability, state, claims, decisions, note}`. The inner
77
+ `capability` is an edge ID in the pinned Capability Surface. One entry per
78
+ capability is permitted in this bounded profile.
79
+ - Each claim is `{target, basis}`. `target` resolves to a local Bound node; basis
80
+ is nonempty. A useful target label may be `MongoDB Atlas` or `OIDC service`.
81
+ A target need not have the same ID as the product-level capability target.
82
+
83
+ | State | Required claims |
84
+ | --- | --- |
85
+ | `configured` | Exactly one target with known configuration evidence; capability state must be `possible`. |
86
+ | `conflicting` | At least two distinct targets, each evidenced; no selected target. |
87
+ | `unknown`, `omitted`, `redacted`, `out-of-scope` | No claims; the note explains why. |
88
+
89
+ A configuration finding has `subject` equal to the opaque instance ID, `property`
90
+ equal to the capability edge ID and claim values equal to target node IDs. It is
91
+ `known` or `conflicting`. Each cited finding must include the target it supports;
92
+ all of that finding's competing targets must be retained in the binding. All
93
+ known/conflicting findings for that same instance and capability in the Bound
94
+ description's referenced research are checked, including uncited basis items.
95
+ Multiple known findings supporting different targets also form a conflict. A configured
96
+ binding cannot cite a conflicting finding. Missing evidence cannot become an
97
+ unbound assertion. Explicit unbound/absence and multi-target configured slots are
98
+ outside this initial binding profile; preserve such source findings in research
99
+ and describe the coverage limit rather than forcing them into a supported state.
100
+
101
+ `decisions` refers only to research decisions, independently of source findings.
102
+ A human preference is not configuration evidence and cannot resolve a source
103
+ conflict by itself. Corrected source evidence belongs in a new research revision.
104
+ Configuration suffices; no reachability, runtime use or successful deployment is
105
+ asserted or checked. Target suitability and the truth/coverage of source prose
106
+ require inspection; matching references alone do not establish those facts.
107
+
108
+ ## Verification and revisions
109
+
110
+ The existing public APIs accept the new types:
111
+
112
+ - `validateArtefact(value)` checks closed shape, states, identity uniqueness,
113
+ local targets/vocabularies and declared research references.
114
+ - `verifyReferences(value, context)` additionally requires exact research and
115
+ Capability revisions/digests, checks evidence roles, subject/property/target
116
+ correspondence and exclusive groups. Include the Capability's research context
117
+ even when the Bound description cites a later research revision.
118
+ - `encode(value, 'json')` and `decode(text, 'json')` check structure and preserve
119
+ data. They do not imply that external references were checked.
120
+ - `verifySuccessor(previous, next)` checks parent revision/digest and retained
121
+ identities. Description kind cannot change. A retained node cannot change its
122
+ type; a retained capability cannot change endpoints/type. A retained binding
123
+ slot cannot change its capability ID, instance or capability-artifact identity.
124
+ A successor may pin a newer revision of the same Capability artifact and change
125
+ a binding target with new evidence. Check both references and succession.
126
+
127
+ A binding ID denotes the instance's slot for that capability, not an immutable
128
+ edge to one target. Target changes retain the slot ID and component IDs where
129
+ those components are the same. A different connection/capability needs a new ID.
130
+ Old bytes and old references stay unchanged; these pure library functions do not
131
+ write files or enforce history-wide ID reuse, atomic persistence or retention.
132
+ Cross-revision vocabulary changes and newly supplied source meaning still need
133
+ human review. Size/depth limits are the existing 2 MiB / 64-level codec limits,
134
+ not graph hop limits.
135
+
136
+ ## Privacy boundary
137
+
138
+ Supply only permitted, sanitized research. Do not copy actual URLs, IP addresses,
139
+ usernames, passwords, keys or raw settings into any note, label, identifier,
140
+ source locator, filename, HTML, JSON or retained evidence. Use opaque source
141
+ identifiers or sanitized snapshots whose digest describes those actual sanitized
142
+ bytes; never invent a digest of unseen raw material. A source that cannot be
143
+ inspected safely is a coverage limit. No raw-secret store is introduced.
144
+
145
+ Closed shapes and rejection of nonempty extensions prevent designated settings
146
+ fields from being stored, but **validation is not a secret detector**. A secret
147
+ could still be put in ordinary prose or an identifier. Producers must avoid
148
+ collecting it and check all output before retention; #51 owns that workflow.
149
+ Tests use synthetic sentinels, never real secrets. New-description validation and
150
+ reference errors omit input values/keys; parser syntax errors also omit source
151
+ snippets. Do not log raw rejected input or legacy research-validation exceptions.
152
+ Old research records allow arbitrary claim values and retain their existing
153
+ validation contract; sanitization remains essential before calling those APIs.
154
+
155
+ ## Human verification task list
156
+
157
+ Prerequisite: open this branch's [synthetic examples](../../examples/researcher/descriptions/README.md).
158
+ No CLI, inference, credentials, real configuration or live services are needed.
159
+
160
+ - [ ] Open `capability.json`. Expect MongoDB, OIDC and SAML as **possible**, an
161
+ authentication exclusive group and **unknown** inference support, without
162
+ instance bindings.
163
+ - [ ] Open `bound-r1.json` beside `sources.md` and `research-r1.json`. Expect a
164
+ **configured** MongoDB Atlas target, **conflicting** OIDC/SAML targets and
165
+ **unknown** inference. Find the separate OIDC preference; it must not erase
166
+ either source claim. Expect role/product identities, no actual settings.
167
+ - [ ] Open `bound-r2.json` and `research-r2.json`. Expect the same instance and
168
+ database binding ID, a self-hosted MongoDB target and exact predecessor
169
+ references. The original files still show Atlas and the earlier evidence.
170
+ - [ ] Report **Pass / Fail / Blocked**, inspected filenames and any incorrect
171
+ state, exposed value, lost conflict or broken reference. These are developer
172
+ fixtures; passing inspection is not installed Researcher acceptance.
173
+
174
+ ### Maintainer preparation and technical readback
175
+
176
+ From the repository root, use Node.js 22, 24 or 26. Run `npm ci` then
177
+ `npm run build` (exit 0; dependency installation uses the registry). This read-only
178
+ example exercises the library directly, not a skill dependency on a CLI:
179
+
180
+ ```sh
181
+ node --input-type=module <<'JS'
182
+ import {readFileSync} from 'node:fs';
183
+ import {decode, verifyReferences, verifySuccessor} from './dist/index.js';
184
+ const read = name => decode(readFileSync(
185
+ `examples/researcher/descriptions/${name}.json`, 'utf8'), 'json');
186
+ const context = ['research-r1', 'research-r2', 'capability'].map(read);
187
+ const before = read('bound-r1'), after = read('bound-r2');
188
+ verifyReferences(context[2], context);
189
+ verifyReferences(before, context);
190
+ verifyReferences(after, context);
191
+ verifySuccessor(before, after);
192
+ console.log(before.bindings.map(b => b.state).join(', '));
193
+ console.log(before.bindings[0].claims[0].target);
194
+ console.log(after.bindings[0].claims[0].target);
195
+ JS
196
+ ```
197
+
198
+ Expect exit 0 and exactly:
199
+
200
+ ```text
201
+ configured, conflicting, unknown
202
+ urn:target:atlas
203
+ urn:target:mongodb
204
+ ```
205
+
206
+ The readback changes no files; no cleanup is needed. A nonzero exit or different
207
+ states/targets fails this check. `npm test` covers malformed data, unsupported
208
+ YAML, privacy sentinels, conflicting/exclusive selections and revision/reference
209
+ drift. The package check exercises these assets through an installed library.
210
+
211
+ ## Baseline and evidence boundary
212
+
213
+ On 8 November 2026, inspection of installed Researcher skill **0.1.9** found its
214
+ explicit statement that it produces working notes and does not generate validated
215
+ research HTML or Surface definitions. This is a prerequisite blocker for the
216
+ requested installed-artifact journey, not an attempted AI investigation or proof
217
+ of generated artifacts. CLI availability is irrelevant to the standalone skill.
218
+ The authorized known gap is implemented here only at the contract/library layer.
219
+
220
+ The synthetic fixture journey above is the #50 agent rehearsal. It is not
221
+ Researcher-produced findings, an installed-skill rehearsal, human acceptance,
222
+ a real-instance inspection, or evidence of runtime use. #51 must package usable
223
+ standalone artifact production/checking resources; #52 must repeat the actual
224
+ installed conversation and independently read back its saved results.