add final acceptance verification

This commit is contained in:
Marco0300
2026-09-03 13:02:04 +02:00
parent 9622f76977
commit 561efe8855
10 changed files with 718 additions and 1 deletions
+96
View File
@@ -0,0 +1,96 @@
# Phase 17 Final Acceptance
## Decision
**Local acceptance: PASS. Production deployment: BLOCKED / not attempted.**
This decision applies to the repository at commit `9622f769776637a40fdae797adccba91445cd351` (branch `main`). The acceptance run validates the local checkout and bounded, offline pilot behavior. It is not evidence that the application was pushed to the remote repository or deployed to a production host.
## Acceptance matrix
| Area | Local evidence | Result | Production interpretation |
| --- | --- | --- | --- |
| Phases 14: baseline workflow, auth, jobs/events | API regression suite, tenant/auth/job checks | PASS locally | SQLite and the in-process worker remain pilot-only |
| Phase 5: source-adapter safety boundary | Source lifecycle, dry-run, CSV/manual-reference tests | PASS locally | No live source is enabled; terms, approval, rate, retention, and circuit controls remain prerequisites |
| Phase 6: normalization and reversible deduplication | Canonicalization, threshold, merge/reversal and tenant tests | PASS locally | Merge permission, full conflict snapshots, concurrency, and production rollback hardening remain open |
| Phase 7: domain intelligence | PSL/DNS-state/candidate and no-false-availability tests | PASS locally | No production resolver, cache, or authorized availability provider is enabled |
| Phase 8: SSRF-safe website observation | Scanner policy, limits, unsafe-target and history tests | PASS locally | Production egress isolation, DNS-rebinding/redirect testing, durable retention, and monitoring remain open |
| Phase 9: official-site contact observation | Extraction, provenance, false-positive and suppression tests | PASS locally | No SMTP probing or outreach; legal, retention, and production isolation gates remain |
| Phase 10: scoring | Versioned rules, explanations, recalculation and suppression tests | PASS locally | Production approval lifecycle, durable scheduling, snapshots, and rollback remain open |
| Phase 11: operator review workflow | Saved views, review queue, dashboard and bounded bulk-action tests | PASS locally | Production audit completeness, idempotency, per-item outcomes, and queue/count hardening remain open |
| Phase 12: CRM and suppression center | Pipeline, interactions, outcomes, reports, and suppression tests | PASS locally | Record-keeping only; no delivery provider or outbound worker exists |
| Phase 13: evidence-grounded AI assistance | Provider-disabled, evidence/citation, approval, limits, and isolation tests | PASS locally | Provider/DPA, legal, secret-management, evaluation, retention, and operational approval remain required |
| Phase 14: draft-only outreach boundary | Draft/gate/idempotency/no-send tests | PASS locally | Outreach remains disabled; consent/legal basis, provider, delivery feedback, and approval controls are not production-complete |
| Phase 15: deployment/readiness/recovery assets | Backup/restore, readiness, config, shell, and safety checks | PASS locally | Host, TLS/DNS/Virtualmin, off-host backups, monitoring, and operator access are unavailable |
| Phase 16: deterministic pilot benchmark | `scripts/benchmark_phase16.py --no-latency`; synthetic fixture report | PASS locally | Synthetic metrics do not establish production quality, capacity, availability, or SLOs |
| Phase 17: final acceptance | This matrix, bounded capacity smoke, reproducibility and blocker review | PASS locally | Production gate remains blocked until external prerequisites are verified |
## Bounded local capacity smoke
The Phase 17 smoke is deterministic, in-memory, and deliberately bounded. It is a guard against accidental unbounded retention, not a load test or capacity claim.
- Synthetic collection: 1,000 items.
- Requested page size: 100; returned items: 100; `has_more=true`.
- Synthetic large batch: 5,000 input items; retained items: 100; input was truncated.
- Enforced smoke limits: maximum page size 100 and maximum retained batch items 100.
- Smoke result: `bounded=true`.
These figures do **not** measure production throughput, concurrency, queue durability, memory pressure, latency SLOs, availability, or safe operating limits. Production capacity requires a reviewed host profile, representative workload, durable worker/database design, observability, and an approved load-test plan.
## Reproducibility and verification record
The final acceptance collector passed with:
- API suite: **100 tests, exit 0** (`python3 -m unittest discover -v -s apps/api/tests -t apps/api`).
- Phase 16 semantic benchmark without variable timing: **passed**.
- Python compilation of scripts and API modules: **passed**.
- Shell syntax checks for backup, healthcheck, restore, and rollback scripts: **passed**.
- JSON validation for the benchmark and acceptance schemas/reports: **passed**.
- Compose config validation: **passed** (`docker compose -f docker-compose.yml config --quiet`).
- Safety invariants: outreach disabled, no send network path, and tenant routes present: **passed**.
- Git state: acceptance head resolved to `9622f769776637a40fdae797adccba91445cd351`; working-tree status was recorded before documentation edits.
The deterministic benchmark reports 100% normalization accuracy, 100% matching precision/recall, 100% contact precision/recall, 100% website-fixture accuracy, reproducible scoring, and zero tenant leakage. The fixture set is synthetic and small; see `docs/BENCHMARKS.md` for methodology and limitations. Timing observations are local pilot signals only.
Repeatable local checks from the repository root:
```sh
python3 scripts/final_acceptance.py --output /tmp/prospect-final-acceptance.json
python3 scripts/benchmark_phase16.py --no-latency --output /tmp/prospect-phase16.json
python3 -m unittest discover -v -s apps/api/tests -t apps/api
python3 -m compileall -q apps/api apps/web
bash -n scripts/*.sh
docker compose config --quiet
git diff --check
```
## Blockers and prerequisites
### Remote publication
Remote push is blocked by missing repository authentication and unverified permission to push the intended branch. The configured remote is `https://repo.mmcloud.co.za/root/MarketingTool.git`; no push was attempted by this acceptance work. A local commit, passing tests, or a clean diff is not a remote publication. Resolve authentication and branch permission, then verify the remote revision independently.
### Production deployment
Deployment is blocked because no production host, Docker/Compose access, protected deployment directory, or deployment operator is available in this run. Before promotion, verify all of the following:
- reviewed remote revision and release owner;
- patched Linux host with Docker Engine/Compose v2, adequate CPU/RAM/disk, firewalling, and restricted Docker access;
- Virtualmin or equivalent perimeter, DNS control, HTTPS certificates and renewal monitoring, and private API exposure where appropriate;
- protected environment/secret manager for `SESSION_SECRET` and any one-time bootstrap values; remove bootstrap values after provisioning and rotate the password;
- encrypted off-host backup destination, checksum/restore drill, retention and legal-hold ownership;
- monitoring for health, restarts, resources, auth failures, backups, TLS, migrations, and unexpected egress;
- named rollback owner and approval to restore data if compatibility is established;
- authenticated tenant-isolation smoke tests and migration validation on the target host.
### Legal and provider enablement
Real source, AI, DNS/availability, scanner, or outreach providers are not enabled by this local acceptance. Any future provider requires an allowlisted identity, owner, approved purpose/data class, tenant scope, region/retention terms, rate and cost caps, timeout/retry/circuit policy, secret-manager injection, current product/security/legal approval, terms/DPA review where applicable, and explicit operational enablement. Outreach additionally requires jurisdiction-specific legal review, documented consent or lawful basis, suppression synchronization, human approval, delivery feedback, retention/deletion/legal-hold controls, and a tested kill switch. Until those gates are complete, `AUTOMATED_OUTREACH_ENABLED=false` remains mandatory.
## Rollback decision
**Decision: retain the current local revision; do not promote or roll back.** There is no production deployment to undo. If a future promotion fails health, integrity, tenant-isolation, migration, or smoke validation, stop traffic and writes as appropriate, record the image/config/backup revisions, restore the previously verified compatible image/config first, and restore data only after schema compatibility and incident-owner approval. Never run an older binary against an incompatible newer schema, and never use `docker compose down -v` on a data-bearing environment. Re-run liveness/readiness, authenticated isolation, and integrity checks before re-enabling traffic.
## Scope boundary
Phase 17 completes the **local acceptance documentation and verification boundary**. It does not claim remote push, host provisioning, credential availability, legal approval, provider enablement, or production deployment. Those are separate external gates and must be recorded as evidence in the release checklist before any production go decision.
+16
View File
@@ -267,3 +267,19 @@ Store the report and raw machine-readable samples with the pilot artifacts, incl
### Unresolved publication and deployment prerequisites
Do not report local benchmark or Compose success as deployment. Remote push remains blocked until repository authentication and intended remote/branch permission are supplied. Production deployment remains blocked until the Phase 15 operator prerequisites are verified: reviewed remote revision, Docker/Compose host access, protected deployment directory, secret injection, DNS/TLS/Virtualmin, encrypted off-host backup and restore evidence, monitoring, rollback owner, and operational approval. Record the blocker in the release record and keep the current outbound-disabled configuration.
## Phase 17 final acceptance and capacity smoke
The Phase 17 decision is **local acceptance PASS; production deployment BLOCKED and not attempted**. Evidence is collected at local commit `9622f769776637a40fdae797adccba91445cd351`; see `docs/FINAL_ACCEPTANCE.md` for the matrix and release record. The final collector passed 100 API tests, the no-latency Phase 16 benchmark, Python compilation, shell syntax, JSON validation, Compose config, Git state, and safety invariants.
The capacity smoke is intentionally deterministic and in-memory: 1,000 synthetic items with page size 100 returned 100 and `has_more=true`; a 5,000-item synthetic batch retained 100 and marked truncation. It verifies bounds only. Do not use it to size production hosts, infer throughput/concurrency, set SLOs, or claim durability/availability. A production capacity exercise requires an approved representative workload, host profile, observability, and durable database/worker design.
For reproducibility, retain the commit, fixture/manifest hash, algorithm and rule-set versions, runtime/dependency/image versions, non-secret configuration fingerprint, seed, locale/timezone, rounding/tie-breaking, command, host profile, timestamps, and raw results. Repeat deterministic fixtures in fresh processes and compare serialized output fields exactly. Keep latency/cache results separate from deterministic acceptance and label cache hits as non-fresh observations.
## Phase 17 release blockers and rollback decision
Remote publication remains blocked until repository authentication and intended remote/branch permission are available; no push was attempted. Production remains blocked until a reviewed remote revision, host and Docker/Compose access, protected deployment directory, secret manager, DNS/TLS/Virtualmin perimeter, encrypted off-host backup and restore drill, monitoring, rollback owner, and operational approval are verified. Real source, AI, DNS/availability, scanner, or outreach providers additionally require allowlisting, terms/DPA and legal review, data/retention policy, consent or lawful-basis approval where applicable, rate/cost/circuit controls, and explicit operational enablement. Keep outreach disabled.
**Rollback decision:** retain the local revision; there is no production deployment to undo. If a future promotion fails health, integrity, migration, tenant-isolation, or smoke checks, stop promotion/traffic and writes as needed, restore the previously verified compatible image/config first, and restore data only after compatibility and incident-owner approval. Re-run health, integrity, and authenticated isolation checks before reopening traffic. Never use `docker compose down -v` on a data-bearing environment.
These are separate states: a passing local acceptance run is not a remote push, and a remote push is not a production deployment.
+10
View File
@@ -186,3 +186,13 @@ These controls describe deployment prerequisites and gates; they do not make SQL
- Store raw samples and reports with minimum necessary data and access controls. Redact secrets, full contact values, and unnecessary fixture content from logs and audit records. Benchmark artifacts must not become an implicit source, evidence record, eligibility decision, cache authority, or outreach input.
Phase 16 does not resolve publication or deployment security gates. Remote push remains blocked pending repository authentication and intended remote/branch permission. Production remains blocked pending the Phase 15 reviewed revision, host and Docker/Compose access, protected deployment directory, secret management, DNS/TLS/Virtualmin perimeter, encrypted off-host backup/restore evidence, monitoring, rollback ownership, and explicit operational approval. A local benchmark, Compose config pass, or local commit is not a remote publication or production deployment.
## Phase 17 acceptance security boundary
Phase 17 passed local acceptance at commit `9622f769776637a40fdae797adccba91445cd351`, including 100 API tests, deterministic synthetic benchmark checks, syntax/JSON/Compose validation, and safety invariants for disabled outreach, no send-network path, and tenant routes. The bounded capacity smoke is only an in-memory guard: 1,000 synthetic records are paged at 100 and a 5,000-item synthetic batch retains at most 100. It is not a security/load assessment and proves nothing about production concurrency, availability, isolation under load, or durability.
Reproducibility evidence must bind results to the commit, fixture/manifest hash, algorithm/rule-set versions, runtime/dependency/image versions, non-secret configuration, seed, locale/timezone, rounding, tie-breaking, host profile, and command. Compare deterministic outputs across fresh processes; preserve failures and incomplete runs. Do not treat synthetic precision/recall or local timing as evidence of identity, consent, deliverability, production quality, capacity, or SLO compliance.
Remote push remains blocked by missing repository authentication and unverified branch permission. Production remains blocked until the reviewed revision, protected host/deployment directory, Docker/Compose access, secret-manager injection, DNS/TLS/Virtualmin perimeter, encrypted off-host backup/restore evidence, monitoring, rollback owner, and operational approval exist. Provider enablement also requires allowlisting, owner/purpose/data-class scope, terms/DPA and jurisdiction-specific legal review, lawful-basis/consent policy where applicable, retention/deletion/legal-hold controls, rate/cost/circuit limits, and explicit operational approval. Keep `AUTOMATED_OUTREACH_ENABLED=false` until every gate is complete.
The rollback decision is to retain the verified local revision and not promote it. If a future release fails health, integrity, migration, authorization, or smoke validation, stop traffic/writes as appropriate, preserve redacted evidence, restore the prior compatible image/config first, and restore data only after compatibility and incident-owner approval. A local pass is not a remote publication; a remote publication is not a production deployment.
+13 -1
View File
@@ -1,4 +1,16 @@
# Phase 16 pilot benchmark
# Benchmarks and final acceptance
Phase 17 final acceptance is run with:
```bash
python3 scripts/final_acceptance.py
```
It writes `final_acceptance.latest.json`, validates local artifacts, and records
explicit external blockers. See `docs/FINAL_ACCEPTANCE.md`; capacity numbers are
synthetic smoke bounds only.
## Phase 16 pilot benchmark
Run from the repository root:
@@ -0,0 +1,159 @@
{
"blockers": [
{
"gate": "remote_auth",
"reason": "Remote repository authentication and branch permission are not available to this local acceptance run.",
"status": "blocked"
},
{
"gate": "deployment_access",
"reason": "No production host, Docker/Compose, DNS/TLS, secrets, or deployment access is available; no deployment was attempted.",
"status": "blocked"
},
{
"gate": "real_provider_legal",
"reason": "Real source/provider enablement, consent/legal basis, terms, and operational approval remain explicit gates; outreach stays disabled.",
"status": "blocked"
}
],
"capacity_smoke": {
"bounded": true,
"interpretation": "Deterministic in-memory smoke only; not a production capacity or throughput claim.",
"large_batch": {
"input_items": 5000,
"retained_items": 100,
"truncated": true
},
"limits": {
"max_batch_items_retained": 100,
"max_page_size": 100
},
"pagination": {
"has_more": true,
"requested_page_size": 100,
"returned_items": 100,
"synthetic_total": 1000
}
},
"checks": {
"api_tests": {
"command": [
"/usr/bin/python3",
"-m",
"unittest",
"discover",
"-v",
"-s",
"apps/api/tests",
"-t",
"apps/api"
],
"passed": true,
"status": "passed",
"summary": "exit=0, tests=100"
},
"benchmark_no_latency": {
"command": [
"/usr/bin/python3",
"scripts/benchmark_phase16.py",
"--no-latency",
"--output",
"/tmp/prospect-phase16-acceptance.json"
],
"passed": true,
"status": "passed",
"summary": "exit=0"
},
"compose_config": {
"command": [
"docker",
"compose",
"-f",
"docker-compose.yml",
"config",
"--quiet"
],
"passed": true,
"status": "passed",
"summary": "exit=0"
},
"git_state": {
"branch_status": "exit=0",
"head": "9622f769776637a40fdae797adccba91445cd351",
"passed": true,
"status": "passed",
"working_tree_clean": false
},
"json_validation": {
"files": {
"docs/benchmarks/final_acceptance.schema.json": {
"passed": true,
"status": "valid_json"
},
"docs/benchmarks/phase16.latest.json": {
"passed": true,
"status": "valid_json"
},
"docs/benchmarks/phase16.schema.json": {
"passed": true,
"status": "valid_json"
},
"phase16_schema_contract": {
"passed": true,
"status": "schema_valid"
}
},
"passed": true
},
"py_compile": {
"command": [
"/usr/bin/python3",
"-m",
"py_compile",
"scripts/benchmark_phase16.py",
"scripts/final_acceptance.py",
"apps/api/app/__init__.py",
"apps/api/app/ai_assistance.py",
"apps/api/app/config.py",
"apps/api/app/contact_extractor.py",
"apps/api/app/domain.py",
"apps/api/app/domain_intelligence.py",
"apps/api/app/main.py",
"apps/api/app/scoring.py",
"apps/api/app/sources.py",
"apps/api/app/website_scanner.py"
],
"passed": true,
"status": "passed",
"summary": "exit=0"
},
"safety_invariants": {
"checks": {
"no_send_network": true,
"outreach_disabled": true,
"tenant_routes": true
},
"passed": true
},
"shell_syntax": {
"command": [
"bash",
"-n",
"scripts/backup_sqlite.sh",
"scripts/healthcheck.sh",
"scripts/restore_sqlite.sh",
"scripts/rollback.sh"
],
"passed": true,
"status": "passed",
"summary": "exit=0"
}
},
"limitations": [
"Synthetic capacity smoke measurements do not establish production throughput, concurrency, durability, or availability."
],
"passed": true,
"report": "phase17-final-acceptance",
"scope": "local-repository-acceptance",
"version": 1
}
@@ -0,0 +1,16 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Prospect Platform Phase 17 final acceptance report",
"type": "object",
"required": ["report", "version", "scope", "passed", "checks", "capacity_smoke", "blockers", "limitations"],
"properties": {
"report": {"const": "phase17-final-acceptance"},
"version": {"type": "integer", "const": 1},
"scope": {"const": "local-repository-acceptance"},
"passed": {"type": "boolean"},
"checks": {"type": "object", "additionalProperties": true},
"capacity_smoke": {"type": "object"},
"blockers": {"type": "array", "items": {"type": "object", "required": ["gate", "status", "reason"], "properties": {"gate": {"type": "string"}, "status": {"type": "string"}, "reason": {"type": "string"}}}},
"limitations": {"type": "array", "items": {"type": "string"}}
}
}