From 93fdbbbe92b03531267ba3d96fe9f131b35a397f Mon Sep 17 00:00:00 2001 From: Ishavn Date: Sun, 4 Oct 2026 21:03:24 +0300 Subject: [PATCH] docs: add Mail Hub reference and executable scope drift example --- CHANGELOG.md | 7 ++ PROJECT_PLAN.md | 6 + README.md | 8 ++ TODO.md | 5 + docs/integrations/hlinor-mail-hub-evidence.md | 18 +++ docs/integrations/hlinor-mail-hub.md | 118 ++++++++++++++++++ examples/mail-hub/agreement.md | 8 ++ examples/mail-hub/communication-events.json | 26 ++++ tests/mail-hub-reference.test.ts | 47 +++++++ 9 files changed, 243 insertions(+) create mode 100644 docs/integrations/hlinor-mail-hub-evidence.md create mode 100644 docs/integrations/hlinor-mail-hub.md create mode 100644 examples/mail-hub/agreement.md create mode 100644 examples/mail-hub/communication-events.json create mode 100644 tests/mail-hub-reference.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 4060b59..8b393f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,3 +16,10 @@ All notable changes to this project will be documented in this file. typecheck/test/build pass, and the built worker answers synthetic GET/HEAD with 200, unknown paths with 404, disallowed methods with 405. - No behavioral, runtime-rule, or version changes in this update. + +## 2026-10-04 + +### Added + +- Mail Hub reference documents distinguish private Operator intake from the public browser analyzer. The synthetic scope-drift regression uses existing JSON parsing, analysis rules and review reports; no live connector or production API was added. +- Short README reference link with sanitized source evidence notes. diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md index 04d5089..54020c5 100644 --- a/PROJECT_PLAN.md +++ b/PROJECT_PLAN.md @@ -19,3 +19,9 @@ Security maintenance (SCOPEGUARD-NPM-002): the three confirmed npm advisories are closed by targeted updates (nanoid 3.3.19, yaml 2.8.3, vitest 4.1.11 with its @vitest/* packages), with dependency floors raised in package.json so the safe minimums are protected. No behavioral or runtime-rule changes. + +## Mail Hub reference documentation (2026-10-04) + +Mail Hub reference documents distinguish private Operator intake from the public browser analyzer. The synthetic scope-drift regression uses existing JSON parsing, analysis rules and review reports; no live connector or production API was added. + +No publication, visibility change or production behavior change is included. diff --git a/README.md b/README.md index b87a8d3..d88492d 100644 --- a/README.md +++ b/README.md @@ -352,3 +352,11 @@ ScopeGuard is an early product prototype. The foundation is intentionally local- For the current product boundary, pilot plan and open-source/private add-on split, see [`docs/product-status.md`](docs/product-status.md). The repository is public under the [Apache License 2.0](LICENSE). Release `v0.2.0` contains the open-source export-based pilot foundation, hosted deployment adapter and first-run onboarding tour. + +## Reference integrations + +### Hlinor Mail Hub + +The separate ScopeGuard Operator consumes normalized communication events from Mail Hub without provider credentials. This public core includes an executable export-based scope-drift example. + +→ [Reference integration: email via Hlinor Mail Hub](docs/integrations/hlinor-mail-hub.md) diff --git a/TODO.md b/TODO.md index fa527da..1fc8667 100644 --- a/TODO.md +++ b/TODO.md @@ -8,3 +8,8 @@ - [ ] Decide the pilot feedback loop for issue #9 (public repo funnel). - [ ] Consider lint tooling (none is configured today) once the current dependency-security pass is accepted. + +## Mail Hub reference documentation + +- [x] Verify case study, existing suite, applicable typecheck/build, links and sanitized evidence. +- [ ] Owner review of local branch; external publication/merge requires a separate decision. diff --git a/docs/integrations/hlinor-mail-hub-evidence.md b/docs/integrations/hlinor-mail-hub-evidence.md new file mode 100644 index 0000000..1980832 --- /dev/null +++ b/docs/integrations/hlinor-mail-hub-evidence.md @@ -0,0 +1,18 @@ +# Sanitized evidence notes + +Reviewed 2026-10-04. Provider-neutral intake is implemented in private Operator, while this public example runs the separate public analyzer. + +Private Mail Hub source revision: `fbabd069358ba79bf1eb9e2cad59e76f83e980e4`. +Private implementation/raw reports are not copied into this repository. Digests +identify the reviewed artifacts for an authorized operator; they do not make +private evidence publicly reproducible or independently attest its content. +Historical records are not a new live check. + +| Reviewed source (private unless noted) | SHA-256 | Evidence / limit | +| --- | --- | --- | +| `consumers/scopeguard/source/src/adapters/mail-hub.ts` | `a5f4d92bc8462e90afa34d31b0547d1ad85c4da68329ff57d622f635a8c10027` | Bounded authenticated read, event validation, selection-scoped checkpoints, normalization and review-only persistence. | +| `consumers/scopeguard/source/tests/mail-hub.test.ts` | `f47b9eb27635c7a825d1c05dbc1ee27bbb7bf7f63958d01ee20056c4f2633e89` | Import/review replay, conflict/cursor/mailbox rejection and untrusted message behavior. | +| `docs/stage4-integration-report.md` | `9e02cf36cdeafebe47383e37436abcd0b8bffe169071bdb3492fe484997082b3` | Real local pilot: six messages/two selected chains, no agreement, zero findings; synthetic positive review flow. | +| `evidence/stage4-production/scopeguard-first-run.json` | `84f785bc8ecf8a2c8e1099e5e19eb6d7ed12a0bc44542c4bf9ca06c061d1895e` | Production manual intake imported six, reviewOnly true, externalWrites zero. | +| `evidence/stage4-production/scopeguard-review.json` | `e2a19980d596c16d0edbc2d4e25a91dd6c2a74815f865b3219383f9f169e7610` | Repeat production intake imported zero; external writeback false. | +| `evidence/stage5-production/linux-tests.json` | `5d791212b08dbe3c595e724e5d0dea11b78b4b815c40361768c281bec5bfa6b2` | Saved Linux test report: private Operator 49 tests; not the public-core test count. | diff --git a/docs/integrations/hlinor-mail-hub.md b/docs/integrations/hlinor-mail-hub.md new file mode 100644 index 0000000..51e78b5 --- /dev/null +++ b/docs/integrations/hlinor-mail-hub.md @@ -0,0 +1,118 @@ +# Reference Integration: Email via Hlinor Mail Hub + +## Why a provider-neutral source + +Email-provider authentication and scope analysis are separate responsibilities. +Hlinor Mail Hub normalizes selected mail into communication events; ScopeGuard +compares communication evidence with agreed scope. ScopeGuard remains useful +with ordinary local exports and does not require Mail Hub. + +**Implementation boundary:** the deployed Mail Hub consumer is the separate, +private ScopeGuard Operator service. This public repository is the browser +review workspace and deterministic analyzer; it does not contain Operator's +HTTP adapter, durable cursor store or server worker. The example below exercises +this repository's actual analyzer through its existing JSON export parser. It +is not a claim that the browser app has a live Mail Hub connector. + +## Architecture and event flow + +```text +Mail providers → Mail Hub → normalized communication events + │ + ┌─────────────────┴─────────────────┐ + ▼ ▼ + ScopeGuard Operator selected local JSON export + private intake/store/worker │ + │ ▼ + ▼ public ScopeGuard analyzer + pending review evidence │ + ▼ + evidence-backed human review +``` + +Mail Hub's `list_communication_events` read operation returns schema version, +immutable `event_id`, mailbox/thread/message identity, sequence/timestamp, +direction, sender/recipients, subject/text, deduplication key, attachment +metadata and source freshness. Events label mail as `untrusted_external_content`. +Operator validates the page and selected mailbox/threads before normalization. +Incoming mail is evidence, never an instruction or approval. + +Operator calls `/v1/tools/list_communication_events` with an operator-configured +origin and dedicated read identity. It maps `event_id` to the stored event ID, +retains message/thread/mailbox provenance, uses `team` for outbound and `unknown` +for inbound role, and omits volatile freshness from stored content identity. +It needs no provider IMAP/Gmail/SMTP credentials and does not download attachments. +Existing provider adapters remain separate options. + +## Integration proof: replay and idempotency + +Saved 2026-10-04 acceptance records show six real messages from two selected +chains imported into Operator, then zero new imports on repeat, with zero real +findings and no external writeback. That proves bounded intake/replay, not +successful detection of a real out-of-scope request: no agreement was supplied. + +The reviewed private adapter checkpoints project + mailbox + sorted exact thread +selection. A cursor advances after event/worker/review persistence. Stable event +replay deduplicates; conflicting replay content fails without advancing the +checkpoint. Changing selected threads changes checkpoint identity. Its tests +cover scope/cursor rejection, conflict handling, freshness exclusion and review +queue persistence. These are private Operator guarantees, not browser guarantees. + +[Sanitized evidence notes](hlinor-mail-hub-evidence.md) record source provenance +and the limits of those historical acceptance observations. + +## Product proof: executable scope drift + +The [synthetic agreement](../../examples/mail-hub/agreement.md) includes a public +marketing site and explicitly excludes a partner dashboard. The +[synthetic event](../../examples/mail-hub/communication-events.json) requests +that dashboard. No customer text or operational IDs are used. + +The [regression test](../../tests/mail-hub-reference.test.ts) projects event +identity/text/sender/time into the existing generic JSON message parser, then +calls `validateSources`, `analyzeSources` and `buildReviewReport`. The parser's +`slack` channel selects generic JSON parsing; exported message provenance is +`mail_hub`. No new channel or production adapter is introduced. + +```text +agreed exclusion + incoming dashboard request + ↓ + existing ScopeGuard rules + ↓ + 1 NEW DELIVERABLE scope_drift finding + scopeMatch=excluded; decision=pending + ↓ + human review / evidence report +``` + +The result contains the communication excerpt, source, matched excluded clause, +stable finding ID, severity/confidence, estimated hours and pending decision. +Confidence and hours are rule heuristics, not measured accuracy or delivery cost. +Repeated export gives the same finding ID/result; an agreement including the +dashboard suppresses the finding. This stateless replay demonstration does not +prove durable HTTP import deduplication in the public browser. + +```bash +npm ci +npm test -- tests/mail-hub-reference.test.ts +npm test +npm run typecheck +npm run build +``` + +## Security, privacy and the shared pattern + +Operator performs local persistence and review only; neither a finding nor email +content authorizes external writeback. The public example stays local and has no +network/provider calls. Real exports may contain sensitive communication: obtain +operator authorization and minimize selected data before importing; do not copy +raw private events into public fixtures. + +Within the same Mail Hub workflow, +[Registry](https://github.com/HlinorAI/hlinor-agent-registry) supplies policy +enforcement for internal operations, ScopeGuard reviews scope evidence, and +SheetSentry validates selected XLSX attachments in an isolated processor. +Each component has an independent purpose. Spreadsheet findings, scope findings, +and operation authorization are distinct outputs; none implies permission to +send a message. Live positive scope-drift detection and public-browser live +connector acceptance are not claimed by this reference. diff --git a/examples/mail-hub/agreement.md b/examples/mail-hub/agreement.md new file mode 100644 index 0000000..7ff41d1 --- /dev/null +++ b/examples/mail-hub/agreement.md @@ -0,0 +1,8 @@ +# Example launch site + +## Included +- Public marketing site +- Responsive desktop and mobile layouts + +## Excluded +- No partner dashboard diff --git a/examples/mail-hub/communication-events.json b/examples/mail-hub/communication-events.json new file mode 100644 index 0000000..1b2ddf8 --- /dev/null +++ b/examples/mail-hub/communication-events.json @@ -0,0 +1,26 @@ +[ + { + "schema_version": "1.0", + "event_id": "email:hub:1:message_123", + "source": "email", + "mailbox": 1, + "thread_id": "thread_example", + "message_id": 123, + "sequence": 1, + "timestamp": "2026-10-04T12:00:00Z", + "direction": "inbound", + "sender": "client@example.com", + "recipients": [ + "team@example.com" + ], + "subject": "Additional request", + "text": "Can we also add a lightweight dashboard for partners before launch?", + "trust": "untrusted_external_content", + "deduplication_key": "1:message_123", + "attachment_metadata": [], + "source_freshness": { + "last_sync_at": "2026-10-04T12:05:00Z", + "sync_complete": true + } + } +] diff --git a/tests/mail-hub-reference.test.ts b/tests/mail-hub-reference.test.ts new file mode 100644 index 0000000..f76d7a0 --- /dev/null +++ b/tests/mail-hub-reference.test.ts @@ -0,0 +1,47 @@ +import { readFileSync } from 'node:fs' +import { describe, expect, it } from 'vitest' +import { analyzeSources, validateSources, type SourceDocument } from '../src/analysis' +import { buildReviewReport } from '../src/report' + +// Test-only export projection; the production intake adapter lives in Operator. +const events = JSON.parse(readFileSync(new URL('../examples/mail-hub/communication-events.json', import.meta.url), 'utf8')) as { + event_id: string; text: string; sender: string; timestamp: string; direction: string +}[] +const scope: SourceDocument = { + id: 'agreement_example', name: 'agreement.md', kind: 'scope', format: 'md', + content: readFileSync(new URL('../examples/mail-hub/agreement.md', import.meta.url), 'utf8'), +} +function exportedMessages(items = events): SourceDocument { + return { id: 'mail_hub_export', name: 'mail-hub-events.json', kind: 'messages', format: 'json', channel: 'slack', + // Existing generic JSON message parser is reached through the slack channel. + // This does not claim the browser has a mail_hub channel or network connector. + content: JSON.stringify(items.map(e => ({ id: e.event_id, text: e.text, user: e.sender, + channel: 'mail_hub', timestamp: e.timestamp }))) } +} + +describe('Mail Hub reference export through the existing public analyzer', () => { + it('finds an excluded deliverable and exports evidence for human review', () => { + const sources = [scope, exportedMessages()] + expect(validateSources(sources).errors).toEqual([]) + const result = analyzeSources(sources) + expect(result.messagesCompared).toBe(1) + expect(result.findings).toHaveLength(1) + const finding = result.findings[0]! + expect(finding).toMatchObject({ category: 'scope_drift', type: 'NEW DELIVERABLE', + scopeMatch: 'excluded', decision: 'pending', reviewed: false }) + expect(finding.excerpt).toContain('dashboard') + expect(finding.scope).toContain('No partner dashboard') + expect(finding.source).toContain('mail_hub') + const report = buildReviewReport('Example launch site', sources, result, result.findings) + expect(report).toContain('dashboard') + expect(report).toContain('No partner dashboard') + }) + + it('preserves finding identity on repeat export and suppresses an included deliverable', () => { + const first = analyzeSources([scope, exportedMessages()]) + const replay = analyzeSources([scope, exportedMessages()]) + expect(replay).toEqual(first) + const included = { ...scope, content: '# Scope\n## Included\n- Partner dashboard' } + expect(analyzeSources([included, exportedMessages()]).findings).toHaveLength(0) + }) +})