diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 48a20b8..6c45c51 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,40 +2,41 @@ name: Deploy Lighthouse to Cloudflare on: workflow_dispatch: - push: - branches: - - main -jobs: - gate: - if: github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, '[deploy lighthouse]') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v6 - with: - node-version: 20 - cache: npm - - run: npm ci - - run: npm run typecheck - - run: npm test +concurrency: + group: lighthouse-production + cancel-in-progress: false +jobs: deploy: - needs: gate runs-on: ubuntu-latest permissions: contents: read - deployments: write steps: + - name: Require an explicit main-branch dispatch + shell: bash + run: | + if [ "$GITHUB_REF" != "refs/heads/main" ]; then + echo "Production deployment must be dispatched from main." + exit 1 + fi - uses: actions/checkout@v5 - uses: actions/setup-node@v6 with: node-version: 20 cache: npm - run: npm ci - - name: Deploy Worker while preserving provisioned secrets + - run: npm run typecheck + - run: npm test + - name: Deploy Worker while preserving provisioned variables and secrets + id: production_deploy + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + command: deploy --keep-vars --strict + - name: Record the active deployment receipt + if: ${{ always() && steps.production_deploy.outcome != 'skipped' }} uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: deploy + command: deployments status --json diff --git a/AGENTS.md b/AGENTS.md index 10c4d72..a7f6f74 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,8 +28,12 @@ Authority sources in descending order: ## Owner Approval and Operational Safety - Do not commit unless Jamie/the user explicitly approves. -- Do not push or merge unless Jamie/the user explicitly approves. This repository is connected to Cloudflare Workers Builds: the 1.29.3 review-branch push uploaded a preview Worker version, and a push to the Cloudflare-configured production branch may promote an active deployment independently of the checked-in GitHub Actions gate. -- Do not deploy, run `wrangler deploy`, apply D1 migrations, rotate secrets, perform destructive operations, or publish releases unless Jamie/the user explicitly approves. +- Do not push or merge unless Jamie/the user explicitly approves. Git publication is an external mutation: branch pushes can upload Worker versions and create preview URLs even when they do not change active traffic. +- External release-control receipt: on 2026-08-26, the Cloudflare Workers Builds production Deploy command was changed from `npx wrangler deploy` to `npx wrangler versions upload`; durable readback after reload confirmed that both Deploy and Version commands are exactly `npx wrangler versions upload`. No build, upload, or deployment was invoked. +- Cloudflare Workers Builds is authorized only to upload versions and previews. The checked-in manual, main-only, validated, serialized, receipted GitHub workflow is the sole authorized production-promotion path. If the external command becomes inaccessible or differs from the verified value, stop and report `BLOCKED BEFORE MERGE`. +- Do not dispatch the production workflow, run `wrangler deploy`, run `wrangler rollback`, apply D1 migrations, rotate or remove secrets, alter routes/custom domains, change observability, perform destructive operations, or publish releases unless Jamie/the user explicitly approves that action. Direct `wrangler deploy` is not an authorized alternate promotion path. +- `npm run release:upload` and `wrangler versions upload` are non-promoting but not zero-mutation; they require explicit publication approval. +- Any Cloudflare Workers Builds configuration change requires explicit external-change approval and a read-only verification receipt before relying on it. - When code depends on a D1 schema change, a migration requires explicit approval and remote verification before any Worker deployment. - Do not print or commit secret values. - Cross-repository contracts with Agent Smith, BUS Core, buscore-site, or the leads database must be documented when touched. @@ -44,13 +48,15 @@ For any Lighthouse alert, WATCH, analytics question, report failure, service-hea 4. If the approved endpoint, credential source, account context, or tool access is missing, report `ACCESS_BLOCKED`. Do not improvise an endpoint, credential, direct SQL query, or alternate service. 5. Do not fan out across every endpoint. Start with supplied evidence; when live access is approved, use the stored-data `GET /report?view=ceo` diagnostic first and narrow from there. +Canonical Cloudflare identity: account `eb1a8dd5723031d94e57642e3eaaebda`, Worker `buscore-lighthouse`, primary D1 binding `DB` at database ID `e46f2daa-7e97-45a3-9bf0-49003a42850c` named `lighthouse`, and Production Custom Domain `lighthouse.buscore.ca`. An empty Worker Routes list is expected for this Custom Domain. If another account context lacks the Worker, correct the account rather than diagnosing an outage. + Operational constraints: - `GET /report?view=source_health` is ingestion-integrity evidence, not service-probe truth. - `WATCH` is not synonymous with outage; Agent Smith owns WATCH/ALERT/UNAVAILABLE wording, while Lighthouse owns facts and availability. - The current `ADMIN_TOKEN` is broad: it protects report reads and the mutating `POST /campaign`, `POST /notes`, and `POST /report/snapshot` routes. Possession does not authorize writes. - Many GET/HEAD surfaces change evidence. Bare/fleet/site reports refresh stored traffic; report failures can increment errors; artifact HEAD records raw/HEAD truth; update, redirect, artifact, telemetry, and admin-write routes are not passive probes. -- Git publication is not zero-mutation. The 1.29.3 review-branch push triggered Cloudflare Workers Builds, uploaded a Worker preview version, and created preview URLs; future non-production behavior depends on external integration settings. The checked-in workflow's release gate does not govern that separate integration; treat a merge or production-branch push as potentially production-deploying until the Cloudflare build settings are explicitly verified. +- Git publication is not zero-mutation. The 1.29.3 `main` merge proved that the former Workers Builds production command could promote active traffic independently of the checked-in gate. Durable readback on 2026-08-26 confirmed that both non-production and production publication now use `npx wrangler versions upload`. Pushes still create version or preview state, while active production promotion is reserved for the explicitly approved manual GitHub workflow. Any future external-setting drift reinstates `BLOCKED BEFORE MERGE`. - Lighthouse, Agent Smith, BUS Core, buscore-site, and tgc-site are separate failure domains. Do not infer a cross-service outage from one unavailable layer. --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aa9a59..c8c2063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,26 @@ # Changelog +## [1.29.4] - 2026-08-26 + +- Recorded the owner-approved read-only Cloudflare audit showing that Workers Builds build `793715ef-6123-4d98-a4a7-797634d07812`, sourced from merged `main` commit `59231d09084d0fa4db71012b6f29550886c5b605`, automatically ran `npx wrangler deploy` and promoted Worker version `ba611ac1-653d-47a2-a465-a85f4124b6b6` to 100% of production traffic. +- Verified `lighthouse.buscore.ca` as an active Production Custom Domain rather than a Worker Route, verified the active `5 0 * * *` cron, and reconciled the deployed D1 and R2 binding identities. +- Pinned Wrangler to Cloudflare account `eb1a8dd5723031d94e57642e3eaaebda` and corrected the primary D1 metadata name from `buscore-lighthouse` to the control-plane name `lighthouse` while preserving binding `DB` and database ID `e46f2daa-7e97-45a3-9bf0-49003a42850c`. +- Removed the ambiguous direct `deploy` package command and added explicit `release:upload`, `release:status`, and `release:history` commands. No direct production-deploy script is provided; production promotion must pass through the validated workflow, which preserves dashboard-managed variables, enables Wrangler strict mode, and returns a machine-readable deployment receipt. Package repository metadata now points to `True-Good-Craft/lighthouse`. +- Made `.github/workflows/deploy.yml` manual-dispatch only, main-only, non-cancelling and serialized, with dependency installation, typechecking, the full test suite, strict production deployment, and an active-deployment JSON receipt in that order. The receipt is attempted whenever the deploy step ran, including an uncertain reported failure; it remains skipped when validation prevents deployment. The workflow relies on the pinned account rather than a second account-ID secret. +- Added deterministic release-control tests covering the pinned Cloudflare identity, D1 metadata, sole manual trigger, main guard, validation/deployment order, serialization, variable preservation, strict deployment, explicit operator commands, and canonical repository metadata. +- Added a rollback-safe operator procedure that requires an explicitly approved immutable version ID, preserves Wrangler's interactive confirmation, verifies the resulting traffic assignment by JSON status receipt, and keeps Git, settings, secrets, domains, D1, and migrations as separate rollback domains. +- Made standalone setup fail safer and more reproducibly: Node.js `20.18.1` or newer is required by the lockfile, dependency installation uses `npm ci`, new environments require an explicit non-production Wrangler configuration, migration examples use the stable `DB` binding, and new-environment migration/secret commands cannot silently inherit the pinned production target. +- Completed the mandatory external release-control prerequisite on 2026-08-26: changed the Cloudflare Workers Builds production Deploy command from `npx wrangler deploy` to `npx wrangler versions upload`, then reloaded the control plane and confirmed that both Deploy and Version commands are exactly `npx wrangler versions upload`. The approved dashboard action was limited to saving this configuration field and re-reading it; no build, upload, or deployment control was invoked. +- Recorded remaining operational gaps: persistent Worker logs and traces are disabled; the unused legacy secret names `DISCORD_WEBHOOK_URL` and `PRICE_GUARD_KEY` remain attached pending a separately approved decision; the GitHub deployment-token path is not proven by repository text; Cloudflare still displays the redirecting historical repository name `True-Good-Craft/buscore-lighthouse`; and the current lockfile install reports one low- and five high-severity npm audit findings whose production relevance and remediation have not yet been assessed. No automatic audit fix is authorized by this bundle. +- No Worker source, endpoint, response contract, auth behavior, storage schema or semantics, retention, schedule, ingestion, report metric, runtime integration, secret value, D1 resource, R2 bucket, custom-domain attachment, migration, or active production traffic changed in this local bundle. Production remains Worker version `ba611ac1-653d-47a2-a465-a85f4124b6b6` until a separately approved deployment occurs. + ## [1.29.3] - 2026-08-26 - Added `OPERATIONS.md` as the canonical Lighthouse access and diagnostic runbook, including ownership boundaries, resource and credential maps, a morning-triage sequence, source/probe interpretation, and standard incident output. - Routed agents and operators through the SOT and runbook before live access, with an explicit `ACCESS_BLOCKED` outcome when approved endpoint, credential, account, or tool access is unavailable. - Documented that the shared `ADMIN_TOKEN` is broad and protects both report reads and administrative writes. - Classified report, manifest, update, redirect, artifact, telemetry, scheduled, D1, deployment, and administrative surfaces by their possible evidence/state side effects. -- Recorded the separately connected Cloudflare Workers Builds path: publishing the review branch automatically uploaded preview Worker version `33f4db25-9faf-435d-a83e-83d7d1c17eac` and created version/branch preview URLs. The Cloudflare check classified the upload as a preview and did not report an active-production promotion; active-production state was not independently control-plane verified. The checked-in GitHub Actions release gate does not govern this integration, so a merge remains potentially production-deploying until the Cloudflare production-branch and deploy-command settings are explicitly verified or the owner accepts that consequence. +- Recorded the separately connected Cloudflare Workers Builds path: publishing the review branch automatically uploaded preview Worker version `33f4db25-9faf-435d-a83e-83d7d1c17eac` and created version/branch preview URLs. The Cloudflare check classified the upload as a preview and did not report an active-production promotion; active-production state was not independently control-plane verified. The checked-in GitHub Actions release gate did not govern this integration, so at that time a merge remained potentially production-deploying until the Cloudflare production-branch and deploy-command settings were explicitly verified or the owner accepted that consequence. - Marked the Phase 2, Phase 3, and policy-alignment documents as scoped historical or policy references rather than current operations authority. - Reconciled cross-repository producer baselines to released BUS Core `1.4.2` and the merged buscore-site `1.4.2` release sync while retaining Agent Smith `0.25.2` as shipped authority; recorded the unresolved BUS Core restore/import signal authority drift rather than legitimizing it. - Added the explicit owner-approved documentation-only bundle exception: code may be omitted only when runtime and contract behavior do not change; SOT, changelog, package, and lockfile remain mandatory, and dummy code changes are forbidden. @@ -28,7 +42,7 @@ - Enforced the TGC privacy contract at ingestion by storing only coarse `small`/`medium`/`large` viewport buckets and event-specific sanitized values for the bounded TGC allowlist. For rolling producer compatibility, exact lowercase `WIDTHxHEIGHT` remains accepted and is immediately bucketed by width before persistence. - Reconciled the SOT and operator policies with standardized-event storage, keyed minute HMAC rate identifiers, CEO use of the optional leads database, the TGC 90-day raw-retention exception, current report families, BUS Core's no-installation-ID product contract, and TGC's active bounded Layer-5 extension. - Ignored the repository-local npm cache used by repeatable verification so dependency checks do not dirty release worktrees. -- No schema change or D1 migration was required for 1.29.1. Worker 1.29.1 was deployed on `2026-08-09T16:41:20.004814Z` as Cloudflare Version ID `ee320e1a-9ceb-4d88-a848-fd7ae0e9e3bc` after typecheck, 162 tests, a Wrangler dry run, and confirmation that no remote migration was pending. The owner-approved release used the authenticated local Wrangler session because the repository currently has no Cloudflare credential secrets configured for GitHub Actions; no secret value was changed. +- No schema change or D1 migration was required for 1.29.1. Worker 1.29.1 was deployed on `2026-08-09T16:41:20.004814Z` as Cloudflare Version ID `ee320e1a-9ceb-4d88-a848-fd7ae0e9e3bc` after typecheck, 162 tests, a Wrangler dry run, and confirmation that no remote migration was pending. The owner-approved release used the authenticated local Wrangler session; at that time, no Cloudflare credential secret was configured for the checked-in GitHub Actions deployment path, and no secret value changed. Current deployment-token availability remains unverified by the 1.29.4 local bundle. ## [1.29.0] - 2026-08-09 diff --git a/OPERATIONS.md b/OPERATIONS.md index c0eb18a..94f7bb2 100644 --- a/OPERATIONS.md +++ b/OPERATIONS.md @@ -1,11 +1,14 @@ # Lighthouse Operations and Diagnostics - Status: current operational runbook -- Scope: Lighthouse analytics access, evidence interpretation, and incident diagnosis -- Runtime baseline: last production deployment recorded in repository history is Lighthouse Worker `1.29.2`; repository documentation release `1.29.3`; CEO report and metric-definition contract `1.1`; current active-production state not independently control-plane verified +- Scope: Lighthouse analytics access, evidence interpretation, incident diagnosis, and release-control boundaries +- Repository baseline: Lighthouse `1.29.4` release-control reconciliation; CEO report and metric-definition contract `1.1` +- Active production baseline: Lighthouse `1.29.3`, Worker version `ba611ac1-653d-47a2-a465-a85f4124b6b6`, 100% traffic, created `2026-08-26T22:57:30.628Z` from `main` commit `59231d09084d0fa4db71012b6f29550886c5b605` through Cloudflare build `793715ef-6123-4d98-a4a7-797634d07812` - Last reconciled: 2026-08-26 -- Live Lighthouse endpoint and Cloudflare control-plane verification during this documentation change: not performed -- Repository-publication evidence: the PR branch push triggered Cloudflare Workers Builds, whose check classified uploaded version `33f4db25-9faf-435d-a83e-83d7d1c17eac` as a preview, reported version/branch preview URLs, and did not report an active-production promotion; this is not independent proof of current active-production state +- Diagnostic access used for this reconciliation: owner-approved authenticated Cloudflare control-plane metadata reads in the verified owning account +- Production interaction: control-plane metadata only; no Lighthouse endpoint, D1 query, log tail, scheduled invocation, deployment, route change, secret operation, or traffic change +- Evidence side effects: no Lighthouse application evidence was refreshed, counted, persisted, archived, or otherwise changed +- Audit snapshot: the preceding 24-hour Cloudflare overview showed 67 invocations and zero Cloudflare platform/runtime errors. This is historical platform telemetry, not proof of Lighthouse endpoint, report, source, probe, or delivery health ## Authority and Purpose @@ -28,7 +31,7 @@ The default diagnostic posture is local and zero-mutation: - Read repository documentation, contracts, fixtures, configuration names, and code. - Inspect local Git state without changing it. - Do not contact production, Cloudflare, Discord, GitHub, Airtable, or another service unless the user has authorized that scope. -- Do not treat `git push` as local-only. This repository's Cloudflare Workers Builds integration uploaded a preview Worker version for the 1.29.3 review-branch push; future branch and production-branch behavior depends on external build settings. +- Do not treat `git push` as local-only. Durable readback on 2026-08-26 confirmed that both non-production and production Workers Builds use `npx wrangler versions upload`. Pushes can therefore upload Worker versions and create previews, although they must not promote active traffic. - Do not run migrations, deployments, scheduled handlers, retention jobs, report snapshots, notes, campaign writes, telemetry submissions, or release downloads during passive diagnosis. - Never print, persist, or commit secret values, raw lead data, identifiers, IP material, or other private payloads. @@ -72,28 +75,66 @@ Sibling paths above describe the audited local checkout layout. If a repository ## Deployed Resource Map -The following identifiers are checked into `wrangler.toml`: +The following production identities were verified by approved read-only control-plane access on 2026-08-26. Repository-controlled values are pinned in `wrangler.toml`; external attachments remain Cloudflare control-plane state. -| Binding or trigger | Configured resource | Purpose | +| Binding, attachment, or trigger | Verified production resource | Authority and purpose | |---|---|---| -| Worker name | `buscore-lighthouse` | Cloudflare Worker service name | -| `DB` | D1 database `buscore-lighthouse` | Primary Lighthouse aggregates and bounded evidence | -| `BUSCORE_LEADS_DB` | D1 database `buscore-leads` | Optional read binding for aggregate inquiry reporting | +| Cloudflare account | `eb1a8dd5723031d94e57642e3eaaebda` | Owning account; pinned in `wrangler.toml` | +| Worker service | `buscore-lighthouse` | Cloudflare Worker service | +| Compatibility | `2026-02-26`; `global_fetch_strictly_public` | Matches checked-in runtime compatibility configuration | +| `DB` | D1 `lighthouse`, ID `e46f2daa-7e97-45a3-9bf0-49003a42850c` | Primary aggregates and bounded evidence; name and ID reconciled in `wrangler.toml` | +| `BUSCORE_LEADS_DB` | D1 `buscore-leads`, ID `75c09145-ce89-418c-b0f0-92afa2835bfd` | Optional aggregate inquiry-report read binding | | `MANIFEST_R2` | R2 bucket `bus-core` | Stable manifest and versioned release artifacts | -| Cron | `5 0 * * *` | Daily traffic capture, rollup, GitHub snapshot, service probes, and retention | +| `GITHUB_REPO` | `True-Good-Craft/TGC-BUS-Core` | Scheduled GitHub snapshot and release-probe repository | +| Production hostname | Custom Domain `lighthouse.buscore.ca` | Active Production Custom Domain; not a Worker Route and not declared in `wrangler.toml` | +| Production `workers.dev` | Enabled and public | Additional external surface; not the canonical consumer or diagnostic endpoint | +| Version and branch previews | Enabled | Externally reachable publication state; do not use as production truth or probe without endpoint-specific approval | +| Cron | `5 0 * * *` | Active at `00:05 UTC`; matches checked-in configuration | +| Persistent logs and traces | Disabled | No retained Worker log/trace evidence is available unless separately approved and enabled | -The checked-in production consumer endpoint is `https://lighthouse.buscore.ca/report` in `../Agent_Smith/wrangler.toml`. Lighthouse's own `wrangler.toml` does not declare the custom hostname/route, so the consumer configuration is the current repository-visible pointer, not independent deployment proof. A control-plane read is required to verify route attachment; do not infer a `workers.dev` URL from the Worker name. +The active Worker secret names are `ADMIN_TOKEN`, `CF_API_TOKEN`, `CF_ZONE_TAG`, `DISCORD_WEBHOOK_URL`, `IGNORED_IP`, `PRICE_GUARD_KEY`, and `TELEMETRY_RATE_LIMIT_SECRET`. Values were not read or exposed. `DISCORD_WEBHOOK_URL` and `PRICE_GUARD_KEY` are not referenced by current source; retaining, rotating, or removing them is a separate secret operation requiring explicit approval. + +Cloudflare currently displays the historical repository name `True-Good-Craft/buscore-lighthouse`; GitHub redirects it to `True-Good-Craft/lighthouse`. Package metadata now names the canonical repository, but changing the external integration label is a separate control-plane action. ## Repository Publication and Deployment Paths -| Path | Proven or repository-visible behavior | Operational boundary | +| Path | Verified or repository-controlled behavior | Operational boundary | |---|---|---| | `.github/workflows/governance.yml` | Runs dependency installation, typechecking, and the full test suite for every PR and `main` push | Validation only; it does not deploy | -| `.github/workflows/deploy.yml` | Triggers on `main` push or manual dispatch; both its validation gate and downstream deploy run only for manual dispatch or the workflow's explicit commit-message release opt-in | This release gate governs only the checked-in deploy workflow | -| Cloudflare Workers Builds, non-production branch | The 1.29.3 review-branch push uploaded a Worker version and produced version/branch preview URLs; the check classified it as a preview and did not report an active-production promotion | This is external preview state created by `git push`, not independent proof of current active-production state. Do not call a preview URL during passive diagnosis because its effective bindings and request side effects have not been separately verified | -| Cloudflare Workers Builds, configured production branch | Cloudflare-managed production branch and deploy-command settings are outside this repository | A merge or production-branch push is potentially active-production-deploying even if the GitHub Actions deploy job skips; require explicit owner approval and either control-plane verification or explicit acceptance of that consequence | +| `.github/workflows/deploy.yml` | Manual dispatch only; refuses non-`main` refs; serializes under `lighthouse-production`; runs install, typecheck, and tests before `wrangler deploy --keep-vars --strict`; attempts `wrangler deployments status --json` whenever the deploy step ran, including an uncertain reported failure | Sole repository-authorized production-promotion path; the external Workers Builds prerequisite was verified on 2026-08-26 | +| `npm run release:upload` | Runs `wrangler versions upload` | Creates external Worker-version or preview state without intentionally changing active traffic | +| `npm run release:status` / `release:history` | Read JSON deployment metadata using the pinned account context | Approved Class 1 control-plane reads only | +| Cloudflare Workers Builds, non-production | Verified `npx wrangler versions upload`; builds enabled; include rule `*`; previews enabled | A branch push creates external preview/version state | +| Cloudflare Workers Builds, production — pre-repair audit | Branch `main`; root `/`; no build command; `npx wrangler deploy`; cache enabled; no build variables or secrets | Automatically promoted the 1.29.3 merge; historical unsafe parallel production authority | +| Cloudflare Workers Builds, production — verified current state | Branch `main`; Deploy command `npx wrangler versions upload`; Version command `npx wrangler versions upload` | Durable readback after reload confirmed both values on 2026-08-26. No build, upload, or deployment was invoked; future pushes may create version state but must not promote traffic | + +The checked-in manual workflow is the sole authorized production-promotion path. Cloudflare Workers Builds is restricted to version uploads by the verified external configuration. The availability and scope of GitHub's `CLOUDFLARE_API_TOKEN` must not be assumed from workflow text; a failed or unverified credential path is `ACCESS_BLOCKED`, not authorization to use another deployment path. Cloudflare Workers Builds uses separately managed integration credentials. + +### Canonical Cloudflare control-plane read sequence + +Use this sequence only after explicit approval for Cloudflare control-plane reads. It contacts Cloudflare but does not intentionally call Lighthouse endpoints or mutate D1/application evidence. + +1. Select account `eb1a8dd5723031d94e57642e3eaaebda`, then select Worker `buscore-lighthouse`. If the Worker is absent under another account context, correct the account; do not classify that as a Lighthouse outage. +2. Read **Deployments** and record the active version ID, traffic percentage, creation time, source commit, and Workers Builds build ID. `npm run release:status` and `npm run release:history` are the repository-provided JSON alternatives for deployment metadata only. +3. Read **Builds** and record the connected repository label, production branch, root directory, build command, production deploy command, version command, non-production include/exclude rules, preview setting, cache setting, and build-variable/secret presence. The mandatory safe production command is exactly `npx wrangler versions upload`. +4. Read **Domains & Routes** and distinguish Custom Domains, Worker Routes, `workers.dev`, and preview URLs. `lighthouse.buscore.ca` is expected as a Production Custom Domain; an empty Worker Routes list is not a missing-domain diagnosis. +5. Read bindings, compatibility settings, and triggers. Match immutable D1 IDs and R2 bucket names against the resource map above; record secret names only, never values; verify cron `5 0 * * *` and both compatibility settings. +6. Read observability enablement separately. Disabled persistent logs/traces means retained evidence is unavailable; it is not proof that no application error occurred. +7. Treat the Worker overview's invocation and platform-error counters as platform telemetry only. A zero platform-error count does not prove Lighthouse application, report, source, probe, or delivery health. +8. Report each fact with its timestamp and classify any inaccessible surface as `ACCESS_BLOCKED`. Do not compensate by calling public or protected Worker endpoints, tailing logs, querying D1 rows, changing settings, uploading a version, or deploying without the corresponding separate approval. -The absence of Cloudflare deployment secrets in GitHub Actions does not disable Cloudflare Workers Builds, which uses separately managed integration credentials. Do not describe the checked-in workflow as the sole deployment control. +### Production rollback and receipt sequence + +A version upload needs no traffic rollback because it does not intentionally promote traffic; its external version/preview state remains part of the publication record. A production deployment rollback is a separate production mutation and is never implied by deployment approval. + +1. Confirm that no `lighthouse-production` workflow run, Workers Builds production job, direct deployment, or rollback is in progress. GitHub concurrency serializes only that workflow; it cannot prevent a direct Wrangler or Workers Builds race. If any production mutation is active or uncertain, stop and wait. +2. With approved Class 1 access, read deployment status/history and record the current version, traffic split, and exact immutable candidate rollback version ID. Never select a rollback target by package label, timestamp guess, or branch name. +3. Obtain explicit owner approval naming that version ID. For the first 1.29.4 production promotion, the audited pre-change candidate is `ba611ac1-653d-47a2-a465-a85f4124b6b6`, but it must still be present and verified before use. +4. Run `npx wrangler rollback --message ""` only under that approval. Do not add `--yes`; preserve the interactive confirmation boundary. +5. Read `npm run release:status` and verify that the intended version receives the expected traffic. Record the JSON receipt and time. A successful command without the readback is not rollback proof. +6. Reconcile repository source separately. Reverting a deployment does not revert Git, Cloudflare Workers Builds settings, secrets, custom domains, D1 data, or migrations. Version 1.29.4 has no migration, so its release-control rollback requires no D1 rollback. + +The pre-merge Workers Builds repair was completed on 2026-08-26: the prior production value `npx wrangler deploy` was replaced with `npx wrangler versions upload`, and reload/readback confirmed that both Deploy and Version commands exactly match the new value. No build, upload, or deployment was invoked. Restoring the prior value requires new explicit external-change approval and immediately reinstates `BLOCKED BEFORE MERGE`; it must never occur as an automatic fallback. `tgc-ops` is not yet safe as an analytics source of truth: its current records include stale future-tense BUS Core telemetry claims and a reversed Lighthouse/buscore-site dependency. Use owning repositories until that separate repository is explicitly reconciled. @@ -105,6 +146,7 @@ The absence of Cloudflare deployment secrets in GitHub Actions does not disable | `LIGHTHOUSE_ADMIN_TOKEN` | Agent Smith runtime | Consumer-side name for the Lighthouse admin credential | | `LIGHTHOUSE_REPORT_URL` | Agent Smith runtime | Canonical report endpoint; checked-in production value points to `https://lighthouse.buscore.ca/report` | | `CF_API_TOKEN` and `CF_ZONE_TAG` | Lighthouse scheduled traffic capture | Cloudflare GraphQL traffic source, not report authentication | +| `CLOUDFLARE_API_TOKEN` | GitHub Actions production workflow | Separately scoped Wrangler deployment credential; presence and scope are not proven by repository text. It is not the Worker runtime `CF_API_TOKEN` | | `GITHUB_REPO` and optional `GITHUB_TOKEN` | Lighthouse scheduled GitHub snapshot/probe configuration | Repository selection and optional API quota; not Lighthouse report authentication | | `TELEMETRY_RATE_LIMIT_SECRET` | Lighthouse ingestion/release counting | Keys rotating abuse-control identifiers; never a diagnostic credential | @@ -125,7 +167,7 @@ This class changes neither local tracked files nor external state. ### Class 1 — approved control-plane reads -Cloudflare deployment, route, binding, cron, log, or D1 metadata reads may establish infrastructure state without intentionally changing Lighthouse application data. They still require explicit authorization, a valid account context, and the least-privileged supported command. A Cloudflare/Wrangler access failure is infrastructure evidence, not a Lighthouse application failure. +Cloudflare deployment, route, binding, cron, log, or D1 metadata reads may establish infrastructure state without intentionally changing Lighthouse application data. They still require explicit authorization, account `eb1a8dd5723031d94e57642e3eaaebda`, and the least-privileged supported command. Use the canonical control-plane read sequence above. A Cloudflare/Wrangler access failure is infrastructure evidence, not a Lighthouse application failure. Do not use direct D1 SQL as a fallback merely because a protected report cannot be accessed. SQL can bypass report semantics, expose data outside the contract, or be accidentally executed as a write. @@ -169,8 +211,9 @@ Do not call these during passive diagnosis: | `POST /metrics/pageview` and `POST /metrics/event` | Return `204` after body capture, then asynchronously validate, rate-limit, and persist. The HTTP response is not acceptance or persistence proof; invalid pageview bodies can still write dropped-invalid evidence | | `POST /telemetry/v1/events` | After basic content-type/size checks, mutates product-telemetry rate-control state before parsing the payload. Valid events then persist deduplication/aggregate state and return an event-ID acknowledgement. The receiver is public and has no diagnostic authentication | | `POST /campaign`, `POST /notes`, `POST /report/snapshot` | Explicit protected writes | -| `git push` to a non-production branch | Connected Cloudflare Workers Builds can upload a preview Worker version and create preview URLs, as observed for the 1.29.3 review branch; the check did not report an active-production promotion, but active-production state was not independently verified | -| Merge or push to the Cloudflare-configured production branch | May run the integration's externally configured deploy command and promote the active production deployment independently of the checked-in GitHub Actions gate | +| `git push` to a non-production branch | Verified Workers Builds configuration runs `npx wrangler versions upload` and can create externally reachable version/branch previews | +| Historical 1.29.3 merge before the external repair | Workers Builds ran `npx wrangler deploy` and promoted production independently of the checked-in GitHub Actions gate | +| Merge or push to `main` after the verified 2026-08-26 repair | Workers Builds runs `npx wrangler versions upload`; it creates external version state but must not promote traffic | | Scheduled handler, D1 command, migration, secret operation, deployment, release | Operational mutation requiring separate explicit approval | The existence of a route in `README.md` or `SOT.md` is not authorization to probe it. @@ -284,24 +327,34 @@ Never report a WATCH as an outage, an access failure as application failure, a s - Lighthouse has no least-privilege report-read credential. The current `ADMIN_TOKEN` also authorizes three write routes. - This repository has no owner-approved, non-echoing production report helper or canonical operator secret-retrieval mechanism. Until one is separately designed and approved, lack of a safe mechanism is `ACCESS_BLOCKED`. -- Lighthouse's `wrangler.toml` does not declare the checked-in consumer hostname, so local configuration alone cannot prove the production route attachment. -- Cloudflare Workers Builds production-branch, build-command, and deploy-command settings are not checked into this repository and were not control-plane verified for this release. The observed branch-preview upload proves the integration is active, so the GitHub Actions gate cannot be used as sole merge-safety evidence. +- The active `lighthouse.buscore.ca` attachment is an externally managed Production Custom Domain rather than checked-in route configuration. It was verified on 2026-08-26, but future attachment changes require another control-plane read. +- Cloudflare Workers Builds commands remain externally managed rather than checked into this repository. Durable readback on 2026-08-26 verified both production Deploy and Version commands as `npx wrangler versions upload`. If that setting becomes inaccessible or differs, report `BLOCKED BEFORE MERGE` until it is reconciled. +- The checked-in manual deployment workflow is the sole authorized production path. The availability and scope of its GitHub `CLOUDFLARE_API_TOKEN` have not been proven by this local bundle. +- Persistent Worker logs and traces are disabled, limiting retained runtime diagnostic evidence. +- Unused legacy secret names `DISCORD_WEBHOOK_URL` and `PRICE_GUARD_KEY` remain attached. Do not inspect, rotate, or remove them without separate approval. +- Cloudflare displays the historical redirecting repository name `True-Good-Craft/buscore-lighthouse`; package metadata now points to canonical `True-Good-Craft/lighthouse`, but the external label remains unreconciled. +- The current lockfile install reports one low- and five high-severity npm audit findings. Their production relevance and safe remediation are unassessed; handle them in a separate dependency audit and never run an automatic audit fix as part of incident diagnosis or release-control repair. - `tgc-ops` analytics/dependency records are stale and cannot yet serve as the trusted cross-repository entry point. - BUS Core `1.4.2` has an explicit producer-side code/SOT authority conflict: its code emits repeatable `restore_attempted`, `restore_completed`, `import_completed`, and `import_failed` events, and the current Lighthouse contract accepts them, but they remain outside BUS Core's SOT-authorized signal set. Lighthouse acceptance does not resolve producer authority. Treat their presence as known drift, not approval or a new metric definition; use BUS Core's SOT, operations runbook, and changelog as authority pending separate resolution. - Agent Smith exposes no raw diagnostic command. Its retained diagnostic formatter is test-only; current private `/report` is the active business/decision product. - Browser producers are fail-soft and provide no end-to-end delivery receipt. - Agent Smith has no independent Discord receipt ledger; a post attempt, log line, or archived monthly snapshot is not receipt proof. -Any helper, token split, route/config reconciliation, cross-repository index repair, receipt mechanism, or automated drift check is a separate future change requiring its owning repository's approval and governance bundle. +Any helper, token split, further route/config change, cross-repository index repair, receipt mechanism, or automated drift check is a separate future change requiring its owning repository's approval and governance bundle. ## Approval Boundaries Separate approval is required before: -- Any production or external-service request. -- Any Cloudflare control-plane, log, or D1 access. +- Any production endpoint or external-service request. +- Any Cloudflare control-plane, log, or D1 access, including `release:status` and `release:history`. - Any endpoint in Class 3. -- Any branch push or PR merge; a branch push can create Cloudflare preview state and did so for the 1.29.3 review branch, while a merge is potentially active-production-deploying until the integration settings are verified. -- Any POST, scheduled invocation, direct SQL, migration, secret operation, deployment, release, commit, push, or cross-repository edit. +- Any commit, branch push, or PR merge. A branch push creates external Worker-version or preview state. +- Any `release:upload`; it creates Cloudflare version state even though it does not intentionally promote traffic. +- Any manual production deployment-workflow dispatch; it is an active-production deployment operation. Direct `wrangler deploy` is not an authorized alternate path. +- Any Cloudflare Workers Builds setting change, custom-domain or route change, observability change, secret operation, direct SQL, migration, scheduled invocation, release, or cross-repository edit. +- Any merge when the last approved Workers Builds readback is missing, superseded by a later setting change, or differs from exactly `npx wrangler versions upload`. Report that state as `BLOCKED BEFORE MERGE`. The last durable verification was 2026-08-26. + +With the Workers Builds production command verified as `npx wrangler versions upload`, a merge still requires explicit owner approval and still creates external version state, but it must not be treated as a production release. Production promotion remains a separate, explicit manual action. -When authorization covers only read-only diagnosis, stop before the first action that can mutate evidence or configuration and ask for the narrower additional approval. +When authorization covers only read-only diagnosis, stop before the first action that can mutate evidence, configuration, version state, or traffic and ask for the narrower additional approval. diff --git a/README.md b/README.md index 1b19eb9..e7fb7a1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # buscore-lighthouse +## 1.29.4 release-control reconciliation + +Repository version 1.29.4 records the verified 1.29.3 production promotion and repairs repository-controlled release authority. Active production is Worker version `ba611ac1-653d-47a2-a465-a85f4124b6b6`, promoted from merged `main` commit `59231d09084d0fa4db71012b6f29550886c5b605` by Cloudflare build `793715ef-6123-4d98-a4a7-797634d07812`. The canonical production hostname is `lighthouse.buscore.ca`, attached as a Production Custom Domain rather than a Worker Route. The additional public `workers.dev` surface and branch/version previews are not canonical diagnostic endpoints. The cron remains `5 0 * * *`; CEO report and metric-definition contract remain `1.1`. + +The repository now pins the verified Cloudflare account, uses the primary D1 control-plane name `lighthouse` without changing its database ID, provides explicit version-upload, status, and history commands, and deliberately provides no direct production-deploy script. The checked-in production workflow is manual-only, main-only, serialized, fully validated, strict, variable-preserving, and receipted. No Worker runtime contract, endpoint, auth, schema, retention, schedule, metric, secret, or active deployment changes in this local bundle. + +> **External release-control verification — 2026-08-26:** the Cloudflare Workers Builds production Deploy command was changed from `npx wrangler deploy` to exactly `npx wrangler versions upload`. Durable readback after reload confirmed that both Deploy and Version commands match. No build, upload, or deployment action was invoked. Git publication can still create version and preview state, but active production promotion is reserved for the checked-in manual workflow. + ## 1.29.3 operations documentation release Repository version 1.29.3 adds the canonical operations and diagnostics runbook and a narrow owner-approved documentation-only governance path. It changes no Worker code, route, contract, auth, binding, storage, retention, schedule, integration, migration, secret, or deployment behavior. The last production deployment recorded in repository history is Lighthouse 1.29.2 (`f07d4af2-a8d6-4df6-adfa-aad7eb9f578d`) with CEO report and metric-definition contract `1.1`; active-production state was not independently control-plane verified during this documentation release. This release does not authorize or require an active-production promotion. Publishing the review branch did cause the separately connected Cloudflare Workers Builds integration to upload a version that its check classified as a preview and for which it reported version/branch preview URLs, as recorded in `CHANGELOG.md` and `OPERATIONS.md`. @@ -26,23 +34,29 @@ The CEO lane changes no existing report view or database table. It uses the curr ## BUS Core minimal product telemetry -Production Worker 1.29.0 retains the 1.27.0 exact event-ID acknowledgement contract with bounded deduplication and aggregate-only product reporting. Current BUS Core product events contain no persistent installation identifier and are limited to first launch, locally deduplicated release/first-success milestones, startup/manual update checks, staged updates, and reliability. Module opens, active days, returning-installation measures, engagement, sessions, retention, and cross-day profiles are prohibited. +Worker 1.29.0 introduced the retained 1.27.0 exact event-ID acknowledgement contract with bounded deduplication and aggregate-only product reporting; verified active Worker 1.29.3 retains that behavior. Current BUS Core product events contain no persistent installation identifier and are limited to first launch, locally deduplicated release/first-success milestones, startup/manual update checks, staged updates, and reliability. Module opens, active days, returning-installation measures, engagement, sessions, retention, and cross-day profiles are prohibited. Migration `0015_minimize_buscore_product_telemetry.sql` was applied before the 2026-07-24 Worker deployment. Product telemetry retains event-ID deduplication keys for 30 UTC-day buckets, aggregate counters for 400 UTC-day buckets, and rate-control buckets for two days. It retains no raw product-event history. ## TGC website analytics -Production Worker 1.29.0 narrows the consented `site_key=tgc_site` lane to aggregate, decision-useful events. Lighthouse is the raw-event and aggregate-report source of truth; the protected operator view remains `GET /report?view=tgc` using the existing `X-Admin-Token` contract. +Worker 1.29.0 introduced the narrowed consented `site_key=tgc_site` lane; verified active Worker 1.29.3 retains it. Lighthouse is the raw-event and aggregate-report source of truth; the protected operator view remains `GET /report?view=tgc` using the existing `X-Admin-Token` contract. The server accepts page views, selected commercial/contact/outbound interest, form start/attempt/outcome, and sanitized errors. Version 1.29.1 accepts a producer-supplied coarse viewport label or, for rolling compatibility, exact lowercase `WIDTHxHEIGHT`; exact dimensions are immediately normalized by width to `small` below 768, `medium` from 768 through 1199, or `large` from 1200 upward, and only that bucket is stored. Event-specific value sanitization turns recognized form, error, and outbound values into bounded categories, unrecognized non-empty values into `other`, and discards absent/blank values or values on the remaining TGC events. Lighthouse discards visitor/session fields and rejects the superseded lifecycle, field-level form, scroll/engagement/section, and first-party web-vital event families. The existing TGC report shape remains available for rollback and historical rows; Smith's CEO lane uses page views and voluntary inquiries only. Raw TGC events are retained for 90 days; other standardized-site raw events retain the general 30-day policy, and rotating keyed rate identifiers are retained for two days. See `TGC_SITE_ANALYTICS_POLICY.md` for the current boundaries. -The repository-visible `.github/workflows/governance.yml` runs `npm ci`, typechecking, and the full test suite for every PR and `main` push. Separately, `.github/workflows/deploy.yml` triggers on `main` pushes and manual dispatch, but its validation gate and downstream Wrangler deployment run only for manual dispatch or an explicitly marked release commit. Neither workflow is the only Cloudflare path: the separately connected Cloudflare Workers Builds integration uploaded a version from the 1.29.3 review branch that its check classified as a preview, and it can deploy from its configured production branch. Those production-branch and deploy-command settings are not checked into this repository and were not read from the control plane during the 1.29.3 documentation release. Treat a merge to `main` as potentially production-deploying until those settings are explicitly verified or the owner accepts that consequence. Migrations remain separate and are never implied by deployment. +## Production release control + +`.github/workflows/governance.yml` validates every pull request and `main` push but does not deploy. `.github/workflows/deploy.yml` is the sole repository-authorized production-promotion path following the verified 2026-08-26 external release-control repair: it is manual-dispatch only, rejects non-`main` refs, serializes deployments under `lighthouse-production`, runs `npm ci`, typechecking, and the full test suite, deploys with `wrangler deploy --keep-vars --strict`, and then attempts `wrangler deployments status --json` whenever the deploy step ran, including an uncertain reported failure. The workflow reads the pinned account from `wrangler.toml`; its deployment token must be verified rather than inferred from workflow text. + +Cloudflare Workers Builds is a separate external publication path. The initial 2026-08-26 audit found non-production branches using `npx wrangler versions upload` with previews enabled while production branch `main` still used `npx wrangler deploy` without a validation build command. Later that day, the production Deploy command was changed to `npx wrangler versions upload`; durable readback after reload confirmed that both Deploy and Version commands are exactly `npx wrangler versions upload`. No build, upload, or deployment action was invoked. Git publication can still create Worker versions and previews, but it must not promote active traffic. Migrations remain separate and are never implied by an upload or deployment. + +## BUS Core artifact traffic truth BUS Core artifact delivery and demand semantics are defined in `BUS_CORE_TRAFFIC_TRUTH.md`. Version 1.25.0 keeps downloads public while separating raw Worker traffic, successful artifact responses, privacy-preserving daily client-network buckets, probable-human intent proxies, confirmed product telemetry, and leads. Migration `0014_add_artifact_traffic_truth.sql` was applied remotely before the 2026-07-18 v1.25.0 deployment. ## BUS Core transition direction -Lighthouse currently serves release data, accepts public-site analytics events, and produces deterministic reports. Migrations 0013 and 0015 plus production Worker 1.29.0 provide strict aggregate-only BUS Core product telemetry and qualified, rate-bounded `/update/check` and artifact-request analytics. +Lighthouse currently serves release data, accepts public-site analytics events, and produces deterministic reports. Migrations 0013 and 0015 plus the current Worker lineage provide strict aggregate-only BUS Core product telemetry and qualified, rate-bounded `/update/check` and artifact-request analytics. The contract accepts only versioned, allowlisted events and fields; rejects unexpected content; enforces retention; and excludes business content such as customer, supplier, employee, item, recipe, invoice, document, filepath, financial, quantity, raw database, and machine-fingerprint data. BUS Core must continue working normally when Lighthouse is unavailable or telemetry is disabled. @@ -766,55 +780,72 @@ The setup commands below create resources, apply migrations, set secrets, start ### 1. Prerequisites -- [Node.js](https://nodejs.org/) >= 18 +- [Node.js](https://nodejs.org/) >= 20.18.1 - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) (installed as dev dependency) - A Cloudflare account ### 2. Install dependencies ```bash -npm install +npm ci ``` -### 3. Create the D1 database +### 3. Create the D1 database for a new environment + +The production database already exists. Do not recreate, rename, or replace it during ordinary setup or diagnosis. Do not run new-environment provisioning through the checked-in production `wrangler.toml`, because it pins the production account. Prepare a separately approved environment-specific Wrangler configuration with its intended `account_id` first, then run: ```bash -npx wrangler d1 create buscore-lighthouse +npx wrangler d1 create YOUR_ENVIRONMENT_DATABASE_NAME --config YOUR_ENVIRONMENT_WRANGLER_CONFIG ``` -Copy the `database_id` from the output and replace `YOUR_D1_DATABASE_ID` in `wrangler.toml`. +Configure that environment's returned database ID explicitly. The production `DB` binding remains database ID `e46f2daa-7e97-45a3-9bf0-49003a42850c`, named `lighthouse`. ### 4. Apply migrations +Local migration uses the stable binding name and cannot reach remote D1. A new remote environment must use its explicit configuration. The checked-in configuration targets production, so its remote command requires separate production-migration approval. Version 1.29.4 has no migration. + ```bash # local (for wrangler dev) -npx wrangler d1 migrations apply buscore-lighthouse --local +npx wrangler d1 migrations apply DB --local -# remote (production) -npx wrangler d1 migrations apply buscore-lighthouse --remote +# separately approved new remote environment +npx wrangler d1 migrations apply DB --remote --config YOUR_ENVIRONMENT_WRANGLER_CONFIG + +# separately approved production only +npx wrangler d1 migrations apply DB --remote ``` ### 5. Set secrets +Production secrets already exist; ordinary setup must not recreate, reveal, or rotate them. For a separately approved new environment, target its explicit configuration: + ```bash -npx wrangler secret put ADMIN_TOKEN -npx wrangler secret put CF_API_TOKEN -npx wrangler secret put TELEMETRY_RATE_LIMIT_SECRET +npx wrangler secret put ADMIN_TOKEN --config YOUR_ENVIRONMENT_WRANGLER_CONFIG +npx wrangler secret put CF_API_TOKEN --config YOUR_ENVIRONMENT_WRANGLER_CONFIG +npx wrangler secret put CF_ZONE_TAG --config YOUR_ENVIRONMENT_WRANGLER_CONFIG +npx wrangler secret put TELEMETRY_RATE_LIMIT_SECRET --config YOUR_ENVIRONMENT_WRANGLER_CONFIG ``` -Add `CF_ZONE_TAG` to your Worker environment configuration before deploying scheduled traffic capture. +`IGNORED_IP` is optional and, when approved for an environment, is provisioned through the same secret mechanism. Do not provision the legacy unreferenced `DISCORD_WEBHOOK_URL` or `PRICE_GUARD_KEY` names in a new environment. ### 6. Configure `wrangler.toml` -Ensure existing bindings are configured for your environment (`DB` and `MANIFEST_R2`). -Also configure `CF_ZONE_TAG` and ensure the scheduled traffic pull is authorized with `CF_API_TOKEN`. +Pin the intended Cloudflare account. Production uses account `eb1a8dd5723031d94e57642e3eaaebda`. Verify `DB`, `BUSCORE_LEADS_DB`, and `MANIFEST_R2` by immutable resource ID or bucket name; do not infer them from the Worker name. Ensure the target environment separately provisions `CF_ZONE_TAG` and `CF_API_TOKEN` for scheduled traffic capture. -### 7. Deploy +### 7. Release inspection, upload, and deployment + +These commands contact Cloudflare and require explicit approval. Status and history are control-plane reads. Upload creates external Worker-version or preview state. Deploy changes active production traffic. ```bash -npm run deploy +npm run release:status +npm run release:history +npm run release:upload ``` +Use `release:upload` only for an approved non-promoting version upload. The only authorized production-promotion path is the manually dispatched `Deploy Lighthouse to Cloudflare` workflow from `main`; it validates before deployment, uses `--keep-vars --strict`, and records an active-deployment JSON receipt. There is intentionally no direct production-deploy package script. No deployment applies a D1 migration or authorizes a secret operation. + +For a production rollback, follow the immutable-version and receipt procedure in `OPERATIONS.md`. Rollback requires a separately approved, explicitly named version ID and post-rollback status verification; it is not bundled into upload or deployment approval. + ### Local development ```bash diff --git a/SOT.md b/SOT.md index 351ae1c..ea39327 100644 --- a/SOT.md +++ b/SOT.md @@ -1,5 +1,17 @@ # Lighthouse — Source of Truth +## Release-control and infrastructure reconciliation — v1.29.4 + +Version 1.29.4 records the owner-approved read-only Cloudflare control-plane audit performed on 2026-08-26 and aligns repository-controlled release tooling with the verified infrastructure. The audit established that the merge of `main` commit `59231d09084d0fa4db71012b6f29550886c5b605` caused Cloudflare Workers Builds build `793715ef-6123-4d98-a4a7-797634d07812` to run the configured production command `npx wrangler deploy` without a validation build command and promote Worker version `ba611ac1-653d-47a2-a465-a85f4124b6b6` to 100% of production traffic. That version was created at `2026-08-26T22:57:30.628Z`. The canonical production hostname is `lighthouse.buscore.ca`, attached as a Production Custom Domain rather than a Worker Route. The additional production `workers.dev` surface and branch/version previews are enabled but are not canonical diagnostic endpoints. The active cron is `5 0 * * *` (`00:05 UTC`). + +The verified owning Cloudflare account is `eb1a8dd5723031d94e57642e3eaaebda`. The primary `DB` binding resolves to D1 database ID `e46f2daa-7e97-45a3-9bf0-49003a42850c`, whose control-plane name is `lighthouse`; the prior checked-in name `buscore-lighthouse` was stale metadata for the same ID. Version 1.29.4 pins the account, reconciles that D1 name, preserves the `BUSCORE_LEADS_DB` and `MANIFEST_R2` bindings, replaces the ambiguous npm deploy command with explicit upload/status/history commands, and deliberately provides no direct production-deploy script. The checked-in production workflow is manual-only, main-only, serialized, and fully validated before deployment. Whenever the deploy step runs, the workflow attempts an active-deployment JSON receipt even if the deploy action reports failure, covering uncertain partial-success states. Production deployment uses Wrangler strict mode and preserves dashboard-managed variables. A deterministic release-control test enforces those repository-owned constraints. + +This is an approved release-control conformance change. It changes operator-visible configuration metadata and release automation, but no Worker source, endpoint, response contract, auth behavior, storage schema or semantics, retention, schedule, ingestion, report metric, runtime integration, secret value, D1 resource ID, R2 bucket, custom-domain attachment, or active production traffic. No migration, secret operation, or Worker promotion is part of the local bundle. Active production remains the verified 1.29.3 Worker until a separately approved production deployment occurs; its Worker source, Wrangler configuration, and migrations are unchanged from 1.29.2. + +`OPERATIONS.md` defines the rollback boundary: select and explicitly approve an immutable Worker version ID, confirm that no deployment mutation is in progress, preserve interactive confirmation, verify resulting traffic by JSON status receipt, and treat Git, Workers Builds settings, secrets, domains, D1 data, and migrations as separate rollback domains. + +**External release-control verification — 2026-08-26:** with separate owner approval, the Cloudflare Workers Builds production Deploy command was changed from `npx wrangler deploy` to exactly `npx wrangler versions upload`. Durable control-plane readback after reload confirmed that both the Deploy command and Version command are exactly `npx wrangler versions upload`. No build, upload, or deployment action was invoked. Workers Builds may now create version or preview state from branch and `main` pushes but must not promote active traffic; the checked-in manual GitHub workflow is the sole authorized production-promotion path. The availability and scope of that workflow's `CLOUDFLARE_API_TOKEN` remain unverified and must not be inferred from workflow text. + ## Canonical operations and diagnostics — v1.29.3 documentation release Version 1.29.3 establishes `OPERATIONS.md` as the canonical runbook, subordinate to this SOT, for choosing Lighthouse diagnostic surfaces, identifying credential and ownership boundaries, classifying evidence side effects, and reporting `ACCESS_BLOCKED` when approved access is unavailable. It also marks the Phase 2, Phase 3, and policy-alignment documents as historical or scoped references rather than current incident authority. @@ -20,7 +32,7 @@ Version 1.29.1 is a conformance patch over the deployed 1.29.0 Worker. Scheduled CEO source coverage is based on the evidence actually available to each metric. The contract retains `full` for a future source that can prove daily completeness. Current sources are sparse event/counter tables, not daily completeness ledgers, so an available current source reports every window as `partial`; an unavailable source reports every window as `unavailable`. Source-dependent inquiry attribution, product-version/failure detail, and service-probe detail are `null` when their source is unavailable rather than plausible empty arrays. For rolling TGC producer compatibility, ingestion accepts either `small`, `medium`, or `large` or an exact lowercase `WIDTHxHEIGHT` value. Exact dimensions are immediately reduced by width to `small` below 768, `medium` from 768 through 1199, or `large` from 1200 upward; only the bucket is stored. Form values are reduced to `infrastructure`, `audit`, `contact`, `general`, or `other`; `js_error` and `outbound_click` use their own bounded category sets with unrecognized non-empty values collapsed to `other`; absent/blank and all other accepted TGC event values are stored as `null`. -Version 1.29.1 changes no D1 schema and required no migration. It was deployed on `2026-08-09T16:41:20.004814Z` as Cloudflare Version ID `ee320e1a-9ceb-4d88-a848-fd7ae0e9e3bc` after typecheck, 162 tests, a Wrangler dry run, and remote confirmation that no migration was pending. The owner-approved release used the authenticated local Wrangler session because the repository currently has no Cloudflare credential secrets configured for GitHub Actions; no secret value was changed. +Version 1.29.1 changes no D1 schema and required no migration. It was deployed on `2026-08-09T16:41:20.004814Z` as Cloudflare Version ID `ee320e1a-9ceb-4d88-a848-fd7ae0e9e3bc` after typecheck, 162 tests, a Wrangler dry run, and remote confirmation that no migration was pending. The owner-approved release used the authenticated local Wrangler session; at that time, no Cloudflare credential secret was configured for the checked-in GitHub Actions deployment path, and no secret value changed. Current deployment-token availability remains unverified by the 1.29.4 local bundle. ## CEO decision-report contract — v1.28.0 route deployed; contract 1.1 deployed with Worker 1.29.1 @@ -58,7 +70,7 @@ The server enforces the TGC event allowlist, production-origin match, path/URL c Lighthouse remains the source of truth. Agent Smith may present this protected aggregate view through `/tgc`. Airtable may receive curated periodic KPI/campaign/content/experiment summaries later, but must not receive raw events or stable identifiers. -Worker 1.29.1 was deployed on `2026-08-09T16:41:20.004814Z` as Cloudflare Version ID `ee320e1a-9ceb-4d88-a848-fd7ae0e9e3bc`; it supersedes the earlier 1.29.0 deployment. The repository-visible `.github/workflows/governance.yml` runs dependency installation, typechecking, and the full test suite for every PR and `main` push. Separately, `.github/workflows/deploy.yml` triggers on `main` pushes and manual dispatch, but its complete typecheck/test gate and downstream deploy run only for manual dispatch or an explicitly marked main-branch commit. A separate Cloudflare Workers Builds Git integration also exists outside those workflows and uses Cloudflare-managed build settings and credentials: the 1.29.3 review-branch push was observed on 2026-08-26 to upload a version that its check classified as a preview and for which it reported version/branch preview URLs; the check did not report an active-production promotion, and active-production state was not independently control-plane verified. A push to the integration's configured production branch may run its configured deploy command and promote the active deployment. The production branch and deploy command are not checked into this repository and were not control-plane verified for the 1.29.3 documentation release, so the GitHub Actions release gate must not be treated as the sole production control. The owner-approved 1.29.1 release used authenticated local Wrangler after the same test gate; no secret value changed. Wrangler deployment preserves separately provisioned Worker secrets. Schema migrations remain a separate, explicit operation. Migration 0015 was remotely verified before Worker 1.27.0 deployment; 1.29.0 and 1.29.1 required no migration. +Worker 1.29.1 was deployed on `2026-08-09T16:41:20.004814Z` as Cloudflare Version ID `ee320e1a-9ceb-4d88-a848-fd7ae0e9e3bc`; it superseded the earlier 1.29.0 deployment. Current repository publication and production-promotion authority is defined by the v1.29.4 section above and `OPERATIONS.md`; the earlier 1.29.3 control-plane uncertainty is retained only as historical evidence. Wrangler production deployment preserves separately provisioned Worker secrets and, through the approved workflow, preserves dashboard-managed variables. Schema migrations remain separate, explicitly approved operations. Migration 0015 was remotely verified before Worker 1.27.0 deployment; versions 1.29.0 through 1.29.4 add no migration. ## BUS Core traffic truth and bounded delivery work — v1.25.0 deployed @@ -138,7 +150,7 @@ Operational access rules: - `HEAD /manifest/core/stable.json` does not increment `metrics_daily.errors`. `HEAD /releases/:filename` still records raw/HEAD artifact truth and therefore is not a zero-mutation diagnostic. - `view=source_health` is telemetry-ingestion integrity, not endpoint liveness. Scheduled `health_checks` and CEO `details.service_probes` are the service-probe evidence. - Agent Smith owns WATCH/ALERT/UNAVAILABLE and report-delivery wording. Lighthouse owns facts, availability, exact windows, source state, limitations, and scheduled probe rows. A WATCH is not automatically an outage. -- Repository publication is operational state, not a zero-mutation diagnostic. Connected Cloudflare Workers Builds uploaded a non-production preview version from the 1.29.3 review branch independently of `.github/workflows/deploy.yml`; future branch behavior depends on external integration settings. Because its production branch and deploy command are control-plane configuration rather than repository state, a merge or production-branch push must be treated as potentially active-production-deploying until explicitly verified and approved. +- Repository publication is operational state, not a zero-mutation diagnostic. The 1.29.3 `main` merge proved that the former Workers Builds production command `npx wrangler deploy` could promote traffic independently of `.github/workflows/deploy.yml`. On 2026-08-26, the production command was changed to `npx wrangler versions upload`, and durable readback after reload confirmed that both production Deploy and Version commands match that value. No build, upload, or deployment was invoked during the change. Pushes can still create version/preview state, while production promotion remains a separate, explicitly approved manual workflow action. If the external setting later becomes inaccessible or differs from the verified value, merge is `BLOCKED BEFORE MERGE` until reconciled. - Known producer-side drift must be reported rather than normalized. BUS Core `1.4.2` emits repeatable `restore_attempted`, `restore_completed`, `import_completed`, and `import_failed` events that the current Lighthouse contract accepts, but those events remain outside BUS Core's SOT-authorized signal set. Lighthouse acceptance does not grant producer authority; BUS Core's SOT governs pending a separate resolution. - Lighthouse, Agent Smith, BUS Core, buscore-site, and tgc-site remain independent failure domains; one unavailable producer, consumer, optional binding, or presentation layer must not be promoted into an unsupported cross-service diagnosis. diff --git a/package-lock.json b/package-lock.json index 14db6a0..4e30ce8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "buscore-lighthouse", - "version": "1.29.3", + "version": "1.29.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "buscore-lighthouse", - "version": "1.29.3", + "version": "1.29.4", "license": "ISC", "devDependencies": { "@cloudflare/workers-types": "^4.20260305.0", diff --git a/package.json b/package.json index 64543f7..5e12b7b 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,27 @@ { "name": "buscore-lighthouse", - "version": "1.29.3", + "version": "1.29.4", "description": "Standalone deterministic metrics worker: manifest proxy + fixed daily counters + protected on-demand reporting.", "scripts": { "dev": "wrangler dev", - "deploy": "wrangler deploy", + "release:upload": "wrangler versions upload", + "release:status": "wrangler deployments status --json", + "release:history": "wrangler deployments list --json", "typecheck": "tsc --noEmit", "build": "tsc --outDir dist --module NodeNext --moduleResolution NodeNext --noEmit false", "test": "npm run build && node --test" }, "repository": { "type": "git", - "url": "git+https://github.com/truegoodcraft/buscore-lighthouse.git" + "url": "git+https://github.com/True-Good-Craft/lighthouse.git" }, "keywords": [], "author": "", "license": "ISC", "bugs": { - "url": "https://github.com/truegoodcraft/buscore-lighthouse/issues" + "url": "https://github.com/True-Good-Craft/lighthouse/issues" }, - "homepage": "https://github.com/truegoodcraft/buscore-lighthouse#readme", + "homepage": "https://github.com/True-Good-Craft/lighthouse#readme", "devDependencies": { "@cloudflare/workers-types": "^4.20260305.0", "ajv": "^8.20.0", diff --git a/tests/release-control.test.mjs b/tests/release-control.test.mjs new file mode 100644 index 0000000..85c9897 --- /dev/null +++ b/tests/release-control.test.mjs @@ -0,0 +1,68 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; + +const wrangler = readFileSync(new URL("../wrangler.toml", import.meta.url), "utf8"); +const workflow = readFileSync(new URL("../.github/workflows/deploy.yml", import.meta.url), "utf8"); +const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); +const packageLock = JSON.parse(readFileSync(new URL("../package-lock.json", import.meta.url), "utf8")); +const sot = readFileSync(new URL("../SOT.md", import.meta.url), "utf8"); +const changelog = readFileSync(new URL("../CHANGELOG.md", import.meta.url), "utf8"); + +test("Cloudflare identity and primary D1 metadata are pinned to the verified control plane", () => { + assert.match(wrangler, /^account_id\s*=\s*"eb1a8dd5723031d94e57642e3eaaebda"$/m); + assert.match( + wrangler, + /\[\[d1_databases\]\]\s*binding\s*=\s*"DB"\s*database_name\s*=\s*"lighthouse"\s*database_id\s*=\s*"e46f2daa-7e97-45a3-9bf0-49003a42850c"/m + ); +}); + +test("production deployment is manual, main-only, serialized, gated, and receipted", () => { + const triggerBlock = workflow + .slice(workflow.indexOf("on:"), workflow.indexOf("concurrency:")) + .trim() + .replace(/\r\n/g, "\n"); + assert.equal(triggerBlock, "on:\n workflow_dispatch:"); + assert.match(workflow, /group:\s*lighthouse-production/); + assert.match(workflow, /cancel-in-progress:\s*false/); + assert.match(workflow, /GITHUB_REF[^\n]*refs\/heads\/main/); + assert.doesNotMatch(workflow, /accountId:|CLOUDFLARE_ACCOUNT_ID/); + assert.doesNotMatch(workflow, /deployments:\s*write/); + + const mainGuard = workflow.indexOf("GITHUB_REF"); + const install = workflow.indexOf("npm ci"); + const typecheck = workflow.indexOf("npm run typecheck"); + const tests = workflow.indexOf("npm test"); + const deploy = workflow.indexOf("command: deploy --keep-vars --strict"); + const receipt = workflow.indexOf("command: deployments status --json"); + assert.ok(mainGuard >= 0 && mainGuard < install); + assert.ok(install < typecheck); + assert.ok(typecheck < tests && tests < deploy); + assert.ok(deploy < receipt); + assert.match(workflow, /id:\s*production_deploy/); + assert.match(workflow, /always\(\)[^\n]*steps\.production_deploy\.outcome[^\n]*'skipped'/); +}); + +test("operator scripts expose reads and upload without a direct production bypass", () => { + assert.equal(packageJson.scripts.deploy, undefined); + assert.equal(packageJson.scripts["release:deploy"], undefined); + assert.equal(packageJson.scripts["release:upload"], "wrangler versions upload"); + assert.equal(packageJson.scripts["release:status"], "wrangler deployments status --json"); + assert.equal(packageJson.scripts["release:history"], "wrangler deployments list --json"); + assert.equal(packageJson.repository.url, "git+https://github.com/True-Good-Craft/lighthouse.git"); +}); + +test("the mandatory release-control bundle records the verified external receipt", () => { + assert.equal(packageJson.version, "1.29.4"); + assert.equal(packageLock.version, packageJson.version); + assert.equal(packageLock.packages[""].version, packageJson.version); + assert.match(sot, /^## Release-control and infrastructure reconciliation — v1\.29\.4$/m); + assert.match(changelog, /^## \[1\.29\.4\] - 2026-08-26$/m); + assert.match( + sot, + /\*\*External release-control verification — 2026-08-26:\*\*[\s\S]*Deploy command[\s\S]*Version command[\s\S]*exactly `npx wrangler versions upload`/ + ); + assert.match(sot, /Workers Builds may now create version or preview state[\s\S]*must not promote active traffic/); + assert.match(sot, /`CLOUDFLARE_API_TOKEN` remain unverified/); + assert.doesNotMatch(sot, /production command (?:remains|still uses|still runs) `npx wrangler deploy`/i); +}); diff --git a/wrangler.toml b/wrangler.toml index 6ff6b41..83d10ab 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,4 +1,5 @@ name = "buscore-lighthouse" +account_id = "eb1a8dd5723031d94e57642e3eaaebda" main = "src/index.ts" compatibility_date = "2026-02-26" compatibility_flags = ["global_fetch_strictly_public"] @@ -10,7 +11,7 @@ GITHUB_REPO = "True-Good-Craft/TGC-BUS-Core" [[d1_databases]] binding = "DB" -database_name = "buscore-lighthouse" +database_name = "lighthouse" database_id = "e46f2daa-7e97-45a3-9bf0-49003a42850c" [[d1_databases]]