@gate-forge/pack-playwright 0.7.1 → 0.8.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 (202) hide show
  1. package/README.md +31 -0
  2. package/dist/constants.d.ts +13 -140
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +13 -148
  5. package/dist/constants.js.map +1 -1
  6. package/dist/cypress/plugin.d.ts +53 -0
  7. package/dist/cypress/plugin.d.ts.map +1 -0
  8. package/dist/cypress/plugin.js +369 -0
  9. package/dist/cypress/plugin.js.map +1 -0
  10. package/dist/cypress/spec-scan.d.ts +39 -0
  11. package/dist/cypress/spec-scan.d.ts.map +1 -0
  12. package/dist/cypress/spec-scan.js +301 -0
  13. package/dist/cypress/spec-scan.js.map +1 -0
  14. package/dist/diagnosis.d.ts +39 -0
  15. package/dist/diagnosis.d.ts.map +1 -0
  16. package/dist/diagnosis.js +63 -0
  17. package/dist/diagnosis.js.map +1 -0
  18. package/dist/discovery/adapter-projection.d.ts +13 -0
  19. package/dist/discovery/adapter-projection.d.ts.map +1 -0
  20. package/dist/discovery/adapter-projection.js +84 -0
  21. package/dist/discovery/adapter-projection.js.map +1 -0
  22. package/dist/discovery/config-locations.d.ts +5 -0
  23. package/dist/discovery/config-locations.d.ts.map +1 -0
  24. package/dist/discovery/config-locations.js +19 -0
  25. package/dist/discovery/config-locations.js.map +1 -0
  26. package/dist/discovery/cypress-runner-adapter.d.ts +112 -0
  27. package/dist/discovery/cypress-runner-adapter.d.ts.map +1 -0
  28. package/dist/discovery/cypress-runner-adapter.js +501 -0
  29. package/dist/discovery/cypress-runner-adapter.js.map +1 -0
  30. package/dist/discovery/discover.d.ts +53 -1
  31. package/dist/discovery/discover.d.ts.map +1 -1
  32. package/dist/discovery/discover.js +100 -3
  33. package/dist/discovery/discover.js.map +1 -1
  34. package/dist/discovery/git-ignore.d.ts +13 -0
  35. package/dist/discovery/git-ignore.d.ts.map +1 -0
  36. package/dist/discovery/git-ignore.js +62 -0
  37. package/dist/discovery/git-ignore.js.map +1 -0
  38. package/dist/discovery/index.d.ts +9 -0
  39. package/dist/discovery/index.d.ts.map +1 -1
  40. package/dist/discovery/index.js +9 -0
  41. package/dist/discovery/index.js.map +1 -1
  42. package/dist/discovery/playwright-runner-adapter.d.ts +108 -0
  43. package/dist/discovery/playwright-runner-adapter.d.ts.map +1 -0
  44. package/dist/discovery/playwright-runner-adapter.js +185 -0
  45. package/dist/discovery/playwright-runner-adapter.js.map +1 -0
  46. package/dist/discovery/prepare-barrier.d.ts +522 -0
  47. package/dist/discovery/prepare-barrier.d.ts.map +1 -0
  48. package/dist/discovery/prepare-barrier.js +739 -0
  49. package/dist/discovery/prepare-barrier.js.map +1 -0
  50. package/dist/discovery/pytest-adapter.d.ts.map +1 -1
  51. package/dist/discovery/pytest-adapter.js +6 -2
  52. package/dist/discovery/pytest-adapter.js.map +1 -1
  53. package/dist/discovery/pytest-runner-adapter.d.ts +124 -0
  54. package/dist/discovery/pytest-runner-adapter.d.ts.map +1 -0
  55. package/dist/discovery/pytest-runner-adapter.js +454 -0
  56. package/dist/discovery/pytest-runner-adapter.js.map +1 -0
  57. package/dist/discovery/reconcile.d.ts +80 -11
  58. package/dist/discovery/reconcile.d.ts.map +1 -1
  59. package/dist/discovery/reconcile.js +395 -78
  60. package/dist/discovery/reconcile.js.map +1 -1
  61. package/dist/discovery/runner-env.d.ts +88 -2
  62. package/dist/discovery/runner-env.d.ts.map +1 -1
  63. package/dist/discovery/runner-env.js +142 -4
  64. package/dist/discovery/runner-env.js.map +1 -1
  65. package/dist/discovery/static-discovery.d.ts +38 -3
  66. package/dist/discovery/static-discovery.d.ts.map +1 -1
  67. package/dist/discovery/static-discovery.js +454 -15
  68. package/dist/discovery/static-discovery.js.map +1 -1
  69. package/dist/discovery/supervised-run.d.ts +199 -10
  70. package/dist/discovery/supervised-run.d.ts.map +1 -1
  71. package/dist/discovery/supervised-run.js +350 -39
  72. package/dist/discovery/supervised-run.js.map +1 -1
  73. package/dist/discovery/trusted-config.d.ts +180 -6
  74. package/dist/discovery/trusted-config.d.ts.map +1 -1
  75. package/dist/discovery/trusted-config.js +279 -10
  76. package/dist/discovery/trusted-config.js.map +1 -1
  77. package/dist/discovery/vitest-runner-adapter.d.ts +172 -0
  78. package/dist/discovery/vitest-runner-adapter.d.ts.map +1 -0
  79. package/dist/discovery/vitest-runner-adapter.js +607 -0
  80. package/dist/discovery/vitest-runner-adapter.js.map +1 -0
  81. package/dist/fixture/consumer-runner.d.ts +4 -0
  82. package/dist/fixture/consumer-runner.d.ts.map +1 -0
  83. package/dist/fixture/consumer-runner.js +38 -0
  84. package/dist/fixture/consumer-runner.js.map +1 -0
  85. package/dist/fixture/evidence.d.ts +27 -0
  86. package/dist/fixture/evidence.d.ts.map +1 -1
  87. package/dist/fixture/evidence.js +12 -0
  88. package/dist/fixture/evidence.js.map +1 -1
  89. package/dist/fixture/fixture.d.ts +2 -1
  90. package/dist/fixture/fixture.d.ts.map +1 -1
  91. package/dist/fixture/fixture.js +1 -17
  92. package/dist/fixture/fixture.js.map +1 -1
  93. package/dist/fixture/witness-client.d.ts +6 -174
  94. package/dist/fixture/witness-client.d.ts.map +1 -1
  95. package/dist/fixture/witness-client.js +6 -267
  96. package/dist/fixture/witness-client.js.map +1 -1
  97. package/dist/index.d.ts +9 -6
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +5 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/json.d.ts +6 -12
  102. package/dist/json.d.ts.map +1 -1
  103. package/dist/json.js +6 -17
  104. package/dist/json.js.map +1 -1
  105. package/dist/reporter/project-graph-reporter.d.ts +92 -0
  106. package/dist/reporter/project-graph-reporter.d.ts.map +1 -0
  107. package/dist/reporter/project-graph-reporter.js +92 -0
  108. package/dist/reporter/project-graph-reporter.js.map +1 -0
  109. package/dist/reporter/reporter.cjs.map +1 -1
  110. package/dist/reporter/reporter.d.ts +93 -4
  111. package/dist/reporter/reporter.d.ts.map +1 -1
  112. package/dist/reporter/reporter.js +174 -18
  113. package/dist/reporter/reporter.js.map +1 -1
  114. package/dist/runner-claims.d.ts +13 -0
  115. package/dist/runner-claims.d.ts.map +1 -0
  116. package/dist/runner-claims.js +46 -0
  117. package/dist/runner-claims.js.map +1 -0
  118. package/dist/runner-resolution.d.ts +3 -0
  119. package/dist/runner-resolution.d.ts.map +1 -0
  120. package/dist/runner-resolution.js +14 -0
  121. package/dist/runner-resolution.js.map +1 -0
  122. package/dist/supervisor/client.d.ts +23 -1
  123. package/dist/supervisor/client.d.ts.map +1 -1
  124. package/dist/supervisor/client.js +49 -0
  125. package/dist/supervisor/client.js.map +1 -1
  126. package/dist/supervisor/drain.d.ts +65 -0
  127. package/dist/supervisor/drain.d.ts.map +1 -1
  128. package/dist/supervisor/drain.js +353 -9
  129. package/dist/supervisor/drain.js.map +1 -1
  130. package/dist/supervisor/index.d.ts +7 -3
  131. package/dist/supervisor/index.d.ts.map +1 -1
  132. package/dist/supervisor/index.js +7 -3
  133. package/dist/supervisor/index.js.map +1 -1
  134. package/dist/supervisor/spool.d.ts +65 -2
  135. package/dist/supervisor/spool.d.ts.map +1 -1
  136. package/dist/supervisor/spool.js +47 -0
  137. package/dist/supervisor/spool.js.map +1 -1
  138. package/dist/surface.d.ts +6 -207
  139. package/dist/surface.d.ts.map +1 -1
  140. package/dist/surface.js +6 -264
  141. package/dist/surface.js.map +1 -1
  142. package/dist/vitest/index.d.ts +23 -0
  143. package/dist/vitest/index.d.ts.map +1 -0
  144. package/dist/vitest/index.js +356 -0
  145. package/dist/vitest/index.js.map +1 -0
  146. package/dist/vitest/reporter.d.ts +83 -0
  147. package/dist/vitest/reporter.d.ts.map +1 -0
  148. package/dist/vitest/reporter.js +211 -0
  149. package/dist/vitest/reporter.js.map +1 -0
  150. package/dist/vitest/worker-slot.d.ts +36 -0
  151. package/dist/vitest/worker-slot.d.ts.map +1 -0
  152. package/dist/vitest/worker-slot.js +51 -0
  153. package/dist/vitest/worker-slot.js.map +1 -0
  154. package/dist/witness/adapter-registry.d.ts +6 -50
  155. package/dist/witness/adapter-registry.d.ts.map +1 -1
  156. package/dist/witness/adapter-registry.js +6 -257
  157. package/dist/witness/adapter-registry.js.map +1 -1
  158. package/dist/witness/behavior-request.d.ts +6 -76
  159. package/dist/witness/behavior-request.d.ts.map +1 -1
  160. package/dist/witness/behavior-request.js +6 -273
  161. package/dist/witness/behavior-request.js.map +1 -1
  162. package/dist/witness/behavior.d.ts +6 -48
  163. package/dist/witness/behavior.d.ts.map +1 -1
  164. package/dist/witness/behavior.js +6 -114
  165. package/dist/witness/behavior.js.map +1 -1
  166. package/dist/witness/bin.d.ts +6 -17
  167. package/dist/witness/bin.d.ts.map +1 -1
  168. package/dist/witness/bin.js +6 -168
  169. package/dist/witness/bin.js.map +1 -1
  170. package/dist/witness/browser.d.ts +14 -206
  171. package/dist/witness/browser.d.ts.map +1 -1
  172. package/dist/witness/browser.js +15 -654
  173. package/dist/witness/browser.js.map +1 -1
  174. package/dist/witness/classifications.d.ts +6 -38
  175. package/dist/witness/classifications.d.ts.map +1 -1
  176. package/dist/witness/classifications.js +6 -83
  177. package/dist/witness/classifications.js.map +1 -1
  178. package/dist/witness/env-attestation.d.ts +6 -94
  179. package/dist/witness/env-attestation.d.ts.map +1 -1
  180. package/dist/witness/env-attestation.js +6 -198
  181. package/dist/witness/env-attestation.js.map +1 -1
  182. package/dist/witness/fixture-provider.d.ts +6 -82
  183. package/dist/witness/fixture-provider.d.ts.map +1 -1
  184. package/dist/witness/fixture-provider.js +6 -105
  185. package/dist/witness/fixture-provider.js.map +1 -1
  186. package/dist/witness/loopback-pins.d.ts +6 -75
  187. package/dist/witness/loopback-pins.d.ts.map +1 -1
  188. package/dist/witness/loopback-pins.js +6 -240
  189. package/dist/witness/loopback-pins.js.map +1 -1
  190. package/dist/witness/server.d.ts +8 -26
  191. package/dist/witness/server.d.ts.map +1 -1
  192. package/dist/witness/server.js +24 -3761
  193. package/dist/witness/server.js.map +1 -1
  194. package/dist/witness/types.d.ts +6 -882
  195. package/dist/witness/types.d.ts.map +1 -1
  196. package/dist/witness/types.js +9 -1
  197. package/dist/witness/types.js.map +1 -1
  198. package/examples/overlay-proof.spec.js +75 -0
  199. package/package.json +8 -2
  200. package/python/__pycache__/gateforge_persistence_intents.cpython-312.pyc +0 -0
  201. package/python/__pycache__/gateforge_persistence_intents.cpython-314.pyc +0 -0
  202. package/python/gateforge_pytest_plugin.py +462 -0
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/witness/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/witness/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,mCAAmC,CAAC"}
@@ -1,2 +1,10 @@
1
- export {};
1
+ /**
2
+ * Compatibility re-export: `witness/types` now lives in the runner-neutral
3
+ * `@gate-forge/witness` package (plan 2026-09-25 phase 1).
4
+ *
5
+ * The move is physical, not behavioural: this module forwards every
6
+ * export unchanged so `@gate-forge/pack-playwright`'s published import
7
+ * paths — which consumers pin — keep resolving to the same values.
8
+ */
9
+ export * from '@gate-forge/witness/witness/types';
2
10
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/witness/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/witness/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,mCAAmC,CAAC"}
@@ -0,0 +1,75 @@
1
+ // A complete, self-contained overlay proof test. Copy it into your own
2
+ // `tests/e2e/gateforge/<resource>.<op>.spec.js` and change the surface —
3
+ // the fixture calls never change.
4
+ //
5
+ // The shape is always the same:
6
+ //
7
+ // 1. `gateforgeTest.extend({ surface })` — YOUR half: the selectors
8
+ // that read YOUR rendered UI. The pack ships no selectors.
9
+ // 2. `annotation: { type: 'gateforge', description: '<obligation key>' }`
10
+ // — the claim this test proves. Copy the exact key from
11
+ // `gateforge next` or the report; a test that names no obligation
12
+ // grades nothing.
13
+ // 3. `evidence.ui.*` — the UI action, inside a witness-recorded
14
+ // interval, with the created identity read back from the rendered
15
+ // list (never from suite-declared data).
16
+ // 4. `evidence.visible.confirm(receipt)` — the result a user sees.
17
+ // 5. `evidence.http.observe(...)` — the transport exchange the browser
18
+ // made inside that same interval.
19
+ // 6. `evidence.persistence.verify(receipt)` — the engine observes the
20
+ // server's own echo on the SAME entity; `fieldsMatch` is the
21
+ // postcondition, graded by the engine, not by this test.
22
+ // 7. `evidence.finalize()` — closes the evidence bundle.
23
+ //
24
+ // Every `evidence` call is a witnessed channel. A plain `page.click` is
25
+ // not evidence: nothing then proves what the server stored.
26
+ import { test as gateforgeTest, expect, SURFACE_DESCRIPTOR_VERSION } from '@gate-forge/pack-playwright';
27
+
28
+ // Replace these selectors with your own rendered UI. Every section is
29
+ // required (`validateSurface` refuses an incomplete surface); `{id}`
30
+ // templates are substituted with the entity id the UI action produced.
31
+ const surface = Object.freeze({
32
+ schemaVersion: SURFACE_DESCRIPTOR_VERSION,
33
+ list: {
34
+ path: '/',
35
+ readySelector: 'h1:has-text("Contacts")',
36
+ rowSelector: 'tbody tr',
37
+ idCellIndex: 0,
38
+ fieldCellIndexes: { name: 1, status: 2 },
39
+ },
40
+ create: {
41
+ formPath: '/contacts/new',
42
+ formReadySelector: 'form[action="/contacts"]',
43
+ fields: { name: 'input[name="name"]' },
44
+ submitSelector: 'button[type="submit"]',
45
+ },
46
+ edit: {
47
+ linkSelector: 'a[href$="/edit"]',
48
+ formReadySelectorTemplate: 'form[action="/contacts/{id}"]',
49
+ fields: { name: 'input[name="name"]' },
50
+ saveSelectorTemplate: 'form[action="/contacts/{id}"] button:not([formaction])',
51
+ },
52
+ archive: {
53
+ controlSelectorTemplate: 'form[action="/contacts/{id}/archive"] button',
54
+ },
55
+ status: {
56
+ field: 'status',
57
+ createdValue: 'active',
58
+ archivedValue: 'archived',
59
+ },
60
+ afterAction: { path: '/' },
61
+ deleteFields: { status: 'archived' },
62
+ });
63
+
64
+ const test = gateforgeTest.extend({ surface });
65
+
66
+ test('creates a contact through the rendered UI (persistence:create)', {
67
+ annotation: { type: 'gateforge', description: 'tenant.contacts:persistence:create' },
68
+ }, async ({ evidence }) => {
69
+ const receipt = await evidence.ui.create({ fields: { name: 'Ada' } });
70
+ await evidence.visible.confirm(receipt);
71
+ await evidence.http.observe({ method: 'POST', path: '/contacts' });
72
+ const outcome = await evidence.persistence.verify(receipt);
73
+ expect(outcome.verdictRelevant.fieldsMatch, JSON.stringify(outcome.verdictRelevant)).toBe(true);
74
+ await evidence.finalize();
75
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gate-forge/pack-playwright",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "gateforgeCompatibility": {
5
5
  "supervisedFixtureProtocol": "gateforge.supervised-playwright.v1"
6
6
  },
@@ -27,6 +27,10 @@
27
27
  "types": "./dist/fixture/fixture.d.ts",
28
28
  "import": "./dist/fixture/fixture.js"
29
29
  },
30
+ "./vitest": {
31
+ "types": "./dist/vitest/index.d.ts",
32
+ "import": "./dist/vitest/index.js"
33
+ },
30
34
  "./witness": {
31
35
  "types": "./dist/witness/server.d.ts",
32
36
  "import": "./dist/witness/server.js"
@@ -39,6 +43,7 @@
39
43
  "files": [
40
44
  "bin",
41
45
  "dist",
46
+ "examples",
42
47
  "python"
43
48
  ],
44
49
  "scripts": {
@@ -47,7 +52,8 @@
47
52
  "test": "vitest run"
48
53
  },
49
54
  "dependencies": {
50
- "@gate-forge/core": "^0.7.1",
55
+ "@gate-forge/core": "^0.8.0",
56
+ "@gate-forge/witness": "^0.8.0",
51
57
  "playwright": "1.58.2",
52
58
  "typescript": "^5.9.2",
53
59
  "yaml": "^2.8.1"
@@ -0,0 +1,462 @@
1
+ """Gateforge pytest plugin: per-test witness sessions + proxied ``httpx``.
2
+
3
+ Plan 2026-09-25 phase 3. The plugin gives pytest the SAME supervised
4
+ evidence channel the Playwright pack gives the browser:
5
+
6
+ - Lifecycle: each test writes ``testBegin`` / ``testEnd`` events (test
7
+ identity, outcome, attempt) to the run's lifecycle spool. The trusted
8
+ CLI drain reads the spool and performs the witness's SUPERVISOR calls
9
+ (session open/seal); this process holds no supervisor rights at all.
10
+ - Tagging: the ``gateforge_session`` fixture resolves the
11
+ supervisor-issued session credential for the RUNNING test by the exact
12
+ ``(workerIndex, testId)`` pair (only an OPEN supervisor session
13
+ answers). The ``gateforge_http`` fixture hands the test an
14
+ ``httpx.Client`` whose transport rewrites the app origin onto the
15
+ per-test session proxy origin, so every exchange is attributed to THAT
16
+ session — the same ``session-proxy`` channel the Playwright fixture
17
+ uses.
18
+
19
+ The plugin is INERT without supervised wiring: when the run-scoped
20
+ ``GATEFORGE_*`` variables are absent (plain ``pytest``, collection,
21
+ advisory diagnostics) every hook is a no-op, so enumeration and
22
+ non-witnessed runs behave exactly as without the plugin. A test that
23
+ REQUESTS the fixtures without wiring fails loudly — never silently
24
+ passes unwitnessed.
25
+
26
+ Claims: mapped obligation ids come from the CLI-written
27
+ ``claim-injections.json`` in the run-state dir, keyed by the
28
+ reconciliation key ``<file>#<title path joined by '>'>``. The document
29
+ is read-only here; a broken or absent document contributes nothing.
30
+
31
+ Env contract (all four required for activation):
32
+ - ``GATEFORGE_WITNESS_URL`` witness base URL,
33
+ - ``GATEFORGE_RUN_TOKEN`` the run's submission credential,
34
+ - ``GATEFORGE_STATE_DIR`` absolute run-state dir (spool + claims),
35
+ - ``GATEFORGE_RUN_ID`` the run identity both sides agree on.
36
+
37
+ Optional: ``GATEFORGE_APP_BASE_URL`` (the app origin the transport
38
+ rewrites; without it ``gateforge_http`` uses the session proxy as base).
39
+
40
+ Requires pytest >= 7 (hook wrappers) and, for ``gateforge_http``,
41
+ ``httpx`` importable in the test environment.
42
+ """
43
+
44
+ import json
45
+ import os
46
+ import re
47
+ import time
48
+ import urllib.error
49
+ import urllib.request
50
+
51
+ import pytest
52
+
53
+ WITNESS_URL_ENV = "GATEFORGE_WITNESS_URL"
54
+ RUN_TOKEN_ENV = "GATEFORGE_RUN_TOKEN"
55
+ STATE_DIR_ENV = "GATEFORGE_STATE_DIR"
56
+ RUN_ID_ENV = "GATEFORGE_RUN_ID"
57
+ APP_BASE_URL_ENV = "GATEFORGE_APP_BASE_URL"
58
+
59
+ RUN_HEADER = "x-gateforge-run"
60
+ CLAIM_INJECTIONS_FILE = "claim-injections.json"
61
+
62
+ SESSION_RESOLVE_TIMEOUT_SECONDS = 5.0
63
+ SESSION_RESOLVE_POLL_SECONDS = 0.05
64
+ SPOOL_POLL_SETTLE_SECONDS = 0.05
65
+
66
+
67
+ def _wired():
68
+ """Whether the run-scoped supervised wiring is present.
69
+
70
+ Returns:
71
+ bool: True exactly when every activation variable is set and
72
+ non-empty; False means the plugin stays inert.
73
+ """
74
+ return all(os.environ.get(name) for name in (WITNESS_URL_ENV, RUN_TOKEN_ENV, STATE_DIR_ENV, RUN_ID_ENV))
75
+
76
+
77
+ def _spool_file():
78
+ """The run's lifecycle spool path.
79
+
80
+ Returns:
81
+ str: absolute ``<stateDir>/spool/<runId>/events.jsonl`` path.
82
+ """
83
+ return os.path.join(
84
+ os.environ[STATE_DIR_ENV], "spool", os.environ[RUN_ID_ENV], "events.jsonl"
85
+ )
86
+
87
+
88
+ def _append_event(event):
89
+ """Append one lifecycle event line to the spool (runner side).
90
+
91
+ The line is one JSON object terminated by a newline (the format is
92
+ NUL-safe by construction: ``json.dumps`` escapes control characters).
93
+ A failed append never crashes the run: the drain then simply never
94
+ opens that session and the witness rejects submissions fail-closed.
95
+
96
+ Args:
97
+ event: dict with the spool event fields (kind, testId,
98
+ workerIndex, file, titlePath, project, and for testEnd also
99
+ outcome + attempt; claims when mapped).
100
+
101
+ Returns:
102
+ None.
103
+ """
104
+ try:
105
+ path = _spool_file()
106
+ os.makedirs(os.path.dirname(path), exist_ok=True)
107
+ with open(path, "a", encoding="utf-8") as handle:
108
+ handle.write(json.dumps(event, separators=(",", ":")) + "\n")
109
+ except OSError as error:
110
+ print("[gateforge] cannot append to the lifecycle spool: %s" % error)
111
+
112
+
113
+ def _worker_index(config):
114
+ """The worker slot this process runs in (pytest-xdist aware).
115
+
116
+ Args:
117
+ config: pytest config object (``workerinput`` exists only under
118
+ xdist workers).
119
+
120
+ Returns:
121
+ int: non-negative worker index; 0 for a non-distributed run.
122
+ """
123
+ worker_input = getattr(config, "workerinput", None)
124
+ if not isinstance(worker_input, dict):
125
+ return 0
126
+ raw = str(worker_input.get("workerid", "gw0"))
127
+ digits = "".join(character for character in raw if character.isdigit())
128
+ return int(digits) if digits else 0
129
+
130
+
131
+ def _identity(item):
132
+ """The reconciliation identity of one test item.
133
+
134
+ Args:
135
+ item: the pytest item running.
136
+
137
+ Returns:
138
+ tuple: ``(file, title_path, key)`` where ``file`` is the
139
+ cwd-relative posix path of the test module, ``title_path`` is
140
+ the node id's segment list after the file part, and ``key`` is
141
+ the ``<file>#<title path joined by '>'>`` reconciliation key the
142
+ CLI's claim-injections document is keyed by.
143
+ """
144
+ node_file = item.nodeid.split("::")[0]
145
+ path = getattr(item, "path", None)
146
+ if path is not None:
147
+ node_file = os.path.relpath(str(path), os.getcwd()).replace(os.sep, "/")
148
+ title_path = item.nodeid.split("::")[1:]
149
+ key = "%s#%s" % (node_file, ">".join(title_path))
150
+ return node_file, title_path, key
151
+
152
+
153
+ def _claims_for(key):
154
+ """Mapped obligation ids for one reconciliation key.
155
+
156
+ Args:
157
+ key: the ``<file>#<title path>`` reconciliation key.
158
+
159
+ Returns:
160
+ list[str]: sorted, de-duplicated obligation ids; empty when the
161
+ claims document is absent, unmapped, or malformed (declarations
162
+ never redirect evidence on a broken document).
163
+ """
164
+ path = os.path.join(os.environ[STATE_DIR_ENV], CLAIM_INJECTIONS_FILE)
165
+ try:
166
+ with open(path, encoding="utf-8") as handle:
167
+ document = json.load(handle)
168
+ except (OSError, ValueError):
169
+ return []
170
+ if not isinstance(document, dict):
171
+ return []
172
+ injections = document.get("injections")
173
+ if not isinstance(injections, dict):
174
+ return []
175
+ raw = injections.get(key)
176
+ if not isinstance(raw, list):
177
+ return []
178
+ claims = sorted({claim for claim in raw if isinstance(claim, str) and claim})
179
+ return claims
180
+
181
+
182
+ def _resolve_session(test_id, worker_index):
183
+ """Resolve the supervisor-issued session credential for one test.
184
+
185
+ Polls ``POST /sessions/resolve`` briefly: the drain opens the
186
+ session asynchronously after the ``testBegin`` spool event lands.
187
+ Only an OPEN supervisor session answers; a never-opened or sealed
188
+ session 404s and keeps polling until the bound.
189
+
190
+ Args:
191
+ test_id: the runner test id the spool event carried.
192
+ worker_index: this process's worker slot.
193
+
194
+ Returns:
195
+ dict: the session credential (sessionId, sessionToken, proxyUrl,
196
+ claims, ...).
197
+
198
+ Raises:
199
+ RuntimeError: when no open session answers within the bound —
200
+ fail closed, never a silently unwitnessed "pass".
201
+ """
202
+ request = json.dumps({"testId": test_id, "workerIndex": worker_index}).encode("utf-8")
203
+ deadline = time.monotonic() + SESSION_RESOLVE_TIMEOUT_SECONDS
204
+ last_detail = "no answer"
205
+ while time.monotonic() < deadline:
206
+ call = urllib.request.Request(
207
+ os.environ[WITNESS_URL_ENV].rstrip("/") + "/sessions/resolve",
208
+ data=request,
209
+ headers={"content-type": "application/json", RUN_HEADER: os.environ[RUN_TOKEN_ENV]},
210
+ method="POST",
211
+ )
212
+ try:
213
+ with urllib.request.urlopen(call, timeout=5) as response:
214
+ body = json.loads(response.read().decode("utf-8"))
215
+ if isinstance(body, dict) and body.get("sessionId"):
216
+ return body
217
+ last_detail = "malformed resolve response"
218
+ except urllib.error.HTTPError as error:
219
+ if error.code != 404:
220
+ last_detail = "HTTP %s from /sessions/resolve" % error.code
221
+ except (OSError, ValueError) as error:
222
+ last_detail = str(error)
223
+ time.sleep(SESSION_RESOLVE_POLL_SECONDS)
224
+ raise RuntimeError(
225
+ "gateforge: no open witness session answered for test '%s' (worker %s) within %.0fs (%s) "
226
+ "— run under the supervised window so the drain opens a session per started test"
227
+ % (test_id, worker_index, SESSION_RESOLVE_TIMEOUT_SECONDS, last_detail)
228
+ )
229
+
230
+
231
+ class GateforgeSession:
232
+ """One test's supervisor-issued session credential.
233
+
234
+ Attributes:
235
+ session_id: the witness session id.
236
+ session_token: the per-session submission token.
237
+ proxy_url: the per-test session proxy origin (None when the run
238
+ wired no observation proxy).
239
+ app_base_url: the app origin the proxy fronts (may be empty).
240
+ """
241
+
242
+ def __init__(self, credential, app_base_url):
243
+ self.session_id = str(credential.get("sessionId", ""))
244
+ self.session_token = str(credential.get("sessionToken", ""))
245
+ proxy_url = credential.get("proxyUrl")
246
+ self.proxy_url = str(proxy_url) if isinstance(proxy_url, str) and proxy_url else None
247
+ self.app_base_url = app_base_url or ""
248
+
249
+
250
+ def _proxied_client(session):
251
+ """Build the session-proxied ``httpx.Client`` for one test.
252
+
253
+ The transport rewrites requests addressed to the app origin onto the
254
+ per-test session proxy origin (same loopback discipline as the
255
+ Playwright fixture's page routing), preserving the path, so the
256
+ exchange is observed under THIS test's session. Without an app base
257
+ URL the client addresses the session proxy directly (relative paths).
258
+
259
+ Args:
260
+ session: the resolved GateforgeSession.
261
+
262
+ Returns:
263
+ httpx.Client: the client the test drives (caller closes it).
264
+ """
265
+ import httpx
266
+ from urllib.parse import urlsplit
267
+
268
+ if session.proxy_url is None:
269
+ raise RuntimeError(
270
+ "gateforge: the witness issued no per-session proxy for this run — the run must wire "
271
+ "an observation proxy (proxyTarget) so httpx traffic can be attributed to the session"
272
+ )
273
+ inner = httpx.HTTPTransport()
274
+ app = urlsplit(session.app_base_url) if session.app_base_url else None
275
+ proxy = urlsplit(session.proxy_url)
276
+
277
+ class _SessionProxyTransport(httpx.BaseTransport):
278
+ """Rewrites app-origin requests onto the session proxy origin."""
279
+
280
+ def handle_request(self, request):
281
+ if (
282
+ app is not None
283
+ and request.url.host == app.hostname
284
+ and (request.url.port or (443 if request.url.scheme == "https" else 80))
285
+ == (app.port or (443 if app.scheme == "https" else 80))
286
+ ):
287
+ request.url = request.url.copy_with(host=proxy.hostname, port=proxy.port)
288
+ return inner.handle_request(request)
289
+
290
+ base_url = session.app_base_url or session.proxy_url
291
+ return httpx.Client(base_url=base_url, transport=_SessionProxyTransport(), timeout=30.0)
292
+
293
+
294
+ def _failure_diagnosis(reports):
295
+ """The additive diagnosis of one failed test, from pytest's own report.
296
+
297
+ Args:
298
+ reports: the stashed phase reports of one test.
299
+
300
+ Returns:
301
+ dict: ``errorMessage`` (the longrepr's first line) and
302
+ ``stackFrames`` (at most five ``file:line`` entries), or an empty
303
+ dict when pytest reported no usable text.
304
+ """
305
+ for report in reports:
306
+ longrepr = getattr(report, "longrepr", None)
307
+ if longrepr is None:
308
+ continue
309
+ text = str(longrepr)
310
+ message = text.splitlines()[0].strip() if text else ""
311
+ frames = []
312
+ for line in text.splitlines()[1:]:
313
+ match = re.search(r"([\w./-]+\.py):(\d+)", line)
314
+ if match is None:
315
+ continue
316
+ frame = "%s:%s" % (match.group(1), match.group(2))
317
+ if frame not in frames:
318
+ frames.append(frame)
319
+ if len(frames) == 5:
320
+ break
321
+ if message or frames:
322
+ return {"errorMessage": message, "stackFrames": frames}
323
+ return {}
324
+
325
+
326
+ @pytest.hookimpl(wrapper=True)
327
+ def pytest_runtest_protocol(item, nextitem):
328
+ """Spool ``testBegin`` before, and ``testEnd`` after, one wired test.
329
+
330
+ Args:
331
+ item: the test item about to run.
332
+ nextitem: the next item (pytest protocol argument, unused).
333
+
334
+ Returns:
335
+ The wrapped protocol result, unchanged.
336
+ """
337
+ if not _wired():
338
+ result = yield
339
+ return result
340
+ worker = _worker_index(item.config)
341
+ node_file, title_path, key = _identity(item)
342
+ # The reconciliation key IS the test identity: sidecar claims, the
343
+ # verifier's record→claim join, and the vitest/cypress reporters all
344
+ # name a test `<file>#<title path>`. The pytest node id
345
+ # (`file::test`) is the same test in pytest's own spelling, so a
346
+ # record stamped with it can never join its claim and the obligation
347
+ # stays blocking no matter what the witness observed.
348
+ event = {
349
+ "kind": "testBegin",
350
+ "testId": key,
351
+ "nodeId": item.nodeid,
352
+ "workerIndex": worker,
353
+ "file": node_file,
354
+ "titlePath": title_path,
355
+ "project": None,
356
+ }
357
+ claims = _claims_for(key)
358
+ if claims:
359
+ event["claims"] = claims
360
+ _append_event(event)
361
+ try:
362
+ result = yield
363
+ finally:
364
+ reports = item.__dict__.get("gateforge_reports", [])
365
+ failed = any(report.failed for report in reports)
366
+ skipped = any(report.skipped for report in reports) and not failed
367
+ call_reports = [report for report in reports if report.when == "call"]
368
+ if skipped:
369
+ outcome = "skipped"
370
+ elif failed or not call_reports or not all(report.passed for report in reports if report.when != "teardown"):
371
+ outcome = "failed"
372
+ else:
373
+ outcome = "passed"
374
+ end_event = {
375
+ "kind": "testEnd",
376
+ "testId": key,
377
+ "nodeId": item.nodeid,
378
+ "workerIndex": worker,
379
+ "file": node_file,
380
+ "titlePath": title_path,
381
+ "project": None,
382
+ "outcome": outcome,
383
+ "attempt": max(1, len(call_reports)),
384
+ }
385
+ if outcome == "failed":
386
+ # Additive diagnosis for the CI progress stream and the
387
+ # Gateforge-owned failures artifact: pytest's own longrepr
388
+ # first line plus its `file:line` frames. The raw report is
389
+ # never copied, and the CLI screens the text before it is
390
+ # printed or written.
391
+ end_event.update(_failure_diagnosis(reports))
392
+ _append_event(end_event)
393
+ return result
394
+
395
+
396
+ @pytest.hookimpl(wrapper=True)
397
+ def pytest_runtest_makereport(item, call):
398
+ """Stash each phase report so the protocol hook can grade the test.
399
+
400
+ Args:
401
+ item: the test item the report belongs to.
402
+ call: the test phase (setup/call/teardown) being reported.
403
+
404
+ Returns:
405
+ The wrapped report, unchanged.
406
+ """
407
+ report = yield
408
+ item.__dict__.setdefault("gateforge_reports", []).append(report)
409
+ return report
410
+
411
+
412
+ @pytest.fixture
413
+ def gateforge_session(request):
414
+ """One test's supervisor-issued witness session.
415
+
416
+ Returns:
417
+ GateforgeSession: the resolved credential for the RUNNING test.
418
+
419
+ Raises:
420
+ pytest.fail: when the supervised wiring is absent or no open
421
+ session answers — a fixture user can never silently pass
422
+ unwitnessed.
423
+ """
424
+ if not _wired():
425
+ pytest.fail(
426
+ "gateforge: the gateforge_session fixture requires the supervised wiring "
427
+ "(GATEFORGE_WITNESS_URL / GATEFORGE_RUN_TOKEN / GATEFORGE_STATE_DIR / GATEFORGE_RUN_ID) — "
428
+ "run under 'gateforge test-gates' or the PytestRunnerAdapter"
429
+ )
430
+ # The SAME reconciliation key the lifecycle hook announced: the
431
+ # supervisor opened the session under that id, so resolving by pytest's
432
+ # own node id would never find it.
433
+ _node_file, _title_path, key = _identity(request.node)
434
+ return GateforgeSession(
435
+ _resolve_session(key, _worker_index(request.config)),
436
+ os.environ.get(APP_BASE_URL_ENV, ""),
437
+ )
438
+
439
+
440
+ @pytest.fixture
441
+ def gateforge_http(gateforge_session):
442
+ """An ``httpx.Client`` routed through THIS test's session proxy.
443
+
444
+ Requests to the app origin (or relative requests, when no app base
445
+ URL is wired) travel the per-test session proxy, so the witness
446
+ observes every exchange under this test's session.
447
+
448
+ Args:
449
+ gateforge_session: the resolved session credential fixture.
450
+
451
+ Yields:
452
+ httpx.Client: the proxied client (closed on teardown).
453
+
454
+ Raises:
455
+ RuntimeError: when the run wired no observation proxy — traffic
456
+ would bypass the session channel, which is never silent.
457
+ """
458
+ client = _proxied_client(gateforge_session)
459
+ try:
460
+ yield client
461
+ finally:
462
+ client.close()