Expedify AI Content Engine — build tracker

Plan v1.0 (signed 2026-09-02) · generated 2026-09-03 10:36 · refreshes every 5 min · data: status.json

Current phasePhase B — Truth layer
Steps complete16 / 4535 % of the plan's checklist
Money figures sourced0.0 %187 distinct third-party figures · gate ≥ 95 %
With a scoped lead94 %6 % have no lead yet
Convention disagreements00 self-contradicting pages
Unknown source hosts0need human tiering

Phases

Phase A — Plan to v1.0 (no build)

Complete

7/9 steps

Steps
  • John answers v0.4 §8 open items 1–6 — DONE 2026-09-02: files-only; legal read = Expedify (we supply claim list); cap + short post-mortem; Expedify names reviewer; request Astro read access; prototype deleted
  • Fill v0.4 §9 numbers — DONE 2026-09-02 (cap 10/wk + 5 %; floor indexed+90d+200 impr; cohort 80/50/≤30; margin +15 % or −3 pos; review 8 min/25 pp/wk; Opus ≤20/wk; max-age 90/90/180/365; fail-closed fallbacks; 3 deferrals with triggers) — ADR 0005
  • Measurement source — direct GSC API via service account (Ahrefs = reference only); request added to developer requests §1b
  • Obtain Astro content-collection schema; record its field list in findings.md — moved to Phase C prerequisites (requested, pending Expedify)
  • Client PRD aligned to v1.0 (§6 post-mortem, §7 asks incl. GSC service account)
  • ADRs written in expedify docs/adr/: 0001 files-never-deploys, 0002 legal read = Expedify, 0003 cap + post-mortem, 0004 named reviewer (growth-cap numbers ADR waits on §9)
  • Developer requests drafted: docs/Expedify_Developer_Requests_2026-09-02.md (repo access, reviewer, legal sign-off, release safety, footprint, cap/cohort/conversion)
  • Send the requests to Expedify; track each as a blocked card when execution unfreezes
  • John signs v1.0 → unfreeze (2026-09-02; file renamed to _v1.0.md)

Phase B — Truth layer (plan P1 → components C1)

In progress

started 2026-09-02 · 9/15 steps

Gate: ≥ 95 % of money figures carry a tier 1/2 source; remainder suppressed. Falsified otherwise → Phase D shrinks to sourced pages only.

Steps
  • Define facts: schema — DONE 2026-09-02 docs/content engine/facts.schema.json (tiers 0–3, statuses incl. not_stated, conditional source/second_source/sign_off requirements): {id, claim_type: fee|processing_time|eligibility|convention|validity, value, unit, source_url, authority_tier: 1 govt|2 embassy|3 aggregator, captured_at, max_age_days, verification_status, second_source_url?}; sections reference facts by {{fact:id}} instead of literal numbers
  • scripts/engine/extract_facts.py — DONE 2026-09-02, read-only, 745 pages → 7,521 candidates in data/facts/candidates/, report reports/facts-extraction-2026-09-02.md; 5 unit tests in tests/test_extract_facts.py. Money gate baseline: 3,316 fee facts = 1,658 first-party + 997 not_stated + 550 with a tier-1/2 candidate on page + 111 with none → 661 third-party figures need real sourcing
  • Independent challenge round 1 (12 findings: 3 blockers — empty convention DB, misleading gate arithmetic, tier heuristic; 7 majors) → INCORPORATED 2026-09-02: extractor v2 + schema v0.2 + data/facts/authority_registry.json (112 hosts) + 11 tests on real data. Gate baseline (v2.1): 187 distinct third-party money figures, 0 % captured, 92 % with a scoped lead, 8 % none. 25 convention disagreements (17 stale hubs + 8 self-contradicting driving guides)
  • Independent challenge round 2 → 4 majors + 4 minors (incl. 2 v2 regressions) → INCORPORATED (v2.1, 16 tests, every page schema-validated)
  • Round 3: all 8 confirmed fixed, verdict COMMIT; 3 follow-ups (money ranges, FAQ-question votes, 'in any N-day' windows, road-authority hosts) folded in → v2.2, 17 tests → COMMITTED + pushed 2026-09-02
  • Tier the unknown source hosts — DONE 2026-09-03: 127 hosts tiered (registry 112 → 224 hosts, ccTLD map 140), 0 unknown left; leads 92 % → 94 %, no-lead 11 figures; idaoffice.org registered as related property, never a source
  • Capture script scripts/engine/capture_facts.py — DONE 2026-09-03: fetches lead URLs (cached, polite, honest UA), matches value near a currency/unit marker, confidence = claim word nearby (weak matches never count). First full run: 21 hits / 546 fetches; money gate 0 → ~2 %; travel.state.gov + mofa.go.jp + immi.homeaffairs.gov.au block bots (403), VFS/moi.gov.ae are JS shells, most ministry leads are sections not fee pages
  • Human source queue scripts/engine/source_queue.pyreports/source-queue-2026-09-03.md (~180 figures grouped by lead host and failure reason: value_not_on_lead_page / blocked_403 / js_or_thin_page / no_lead / weak_match_confirm)
  • Source the candidates: convention facts from data/idp-countries-by-convention.json (audited 2026-08-30, tier 1 via UN treaty lists); fees/times from data/genuine_fees_*.json + VisaHQ matrix (tier 3 → needs tier 1/2 confirmation); everything else → human source queue card
  • scripts/engine/truth_gate.py — DONE 2026-09-03 (R1 provenance, R2 second source, R3 max-age, R4 disagreement; merges captures; per-page verdict PASS/HOLD/FAIL + corpus gate). First run: corpus gate NOT YET, 4/187 money figures sourced. Remaining design gap: the 'every rendered number has a fact id' check needs the facts block retrofit (step 7)
  • Write scripts/engine/staleness.py: for live pages, emit a *demotion change* to meta (hide figure → banner → noindex: true) per policy; runs from a timer, opens a W5 card
  • Write scripts/engine/source_watch.py + ops/systemd/expedify-source-watch.{service,timer}: fetch the issuing-body URLs behind top-value facts (start: top 20 by page value), hash the relevant block, diff, open a W2 card with the diff attached
  • Legal/compliance read of IDP-validity + fee statements (owner per §8 item 2)
  • Retrofit run on the corpus; commit facts blocks in tranches (≤ 50 files per PR, playbook order: visa hubs → driving guides → country hubs → tuples)
  • Ledger: SYSTEM.md entry for the timer + scripts

Phase C — Contract + gates (plan P2 → C2, C3 single-brief, C4, C5, C9)

Pending

0/9 steps

Gate: dry-run batch builds clean on the site; applied set == manifest.

Steps
  • Write docs/policies/corpus-admission.md (right-to-exist test) + scripts/engine/admit_brief.py (mechanical parts: sibling payload check, refresh-not-new lookup, query-overlap check vs reports/ SERP data, commercial-value flag from a per-page-type value table)
  • Brief template briefs/_template.yaml with facts_plan: (which fact ids the page will carry and their planned sources)
  • Create path scripts/engine/create_page.py: brief → registry-composed draft via luna-content (Gemma) → validate_page.pytruth_gate.pydedup_gate.py (siblings + competitor corpus via pipelines/query_competitor_corpus.py) → citation_gate.py (only where the page type warrants) → kanban_request_review (opus-reviewer, evidence-ID contract, ≤ 3 rounds)
  • Sampled approval scripts/engine/approve_batch.py: picks k files (start k = batch = 5), prints the 3 questions per file, records verdicts + time-on-page to reviews/approvals/<batch_id>.json; batch-size rule (double after 2 clean, halve on any rejection, any rejection rejects the batch); alarm when median review time < threshold
  • Handoff scripts/engine/handoff.py: copies approved files to handoff/<batch_id>/, writes manifest.json (file, sha256, action, approver, verdicts, redirect_from), idempotent re-run; pin manifest.schema.json
  • Growth-cap + audit log scripts/engine/cap.py: refuses a handoff that would exceed URLs/week or %-modified/week; appends every handoff to reviews/audit-log.jsonl
  • Site-side §6 items 1–6 landed by Expedify's developer (schema read access, build-diff == manifest, atomic release + rollback, kill switch, deploy checks vs indexation watcher, build close-out) — track as one blocked card per item
  • Dry run: 20-page batch through the whole path into handoff/, developer builds it on a preview → measures writer throughput (pages/day) for §9
  • Ledger entries for scripts, board conventions, handoff folder

Phase D — Validation cohort (plan P3 → C6)

Pending

0/5 steps

Gate: ≥ 80 % indexed @ 30 d; ≥ 50 % with ≥ 1 impression-bearing query @ 90 d; no manual action. Fail ⇒ STOP.

Steps
  • Pick 30–60 URLs (page types + hardest tuples) with John/client; record list in findings.md
  • Measurement scripts/engine/measure.py: pull GSC (source per Phase A decision), URL-inspection indexation, conversion events; write data/measure/; per-page cost ledger from Phase C logs
  • Per-page (not sampled) approval for every cohort file
  • Release in tranches over several weeks; robots lifted incrementally by the developer; indexation watcher reporting to aos-notify
  • Hold 8–12 weeks; weekly readout card

Phase E — Improve loop on the cohort (plan P4 → C7, W3, W5)

Pending

0/4 steps

Gate: refreshed beats control at 90 d by the §9 margin; else keep only FIX-FACT/TECHNICAL.

Steps
  • scripts/engine/triage.py: evidence floor check → deterministic typed decision (NO-ACTION default; FIX-FACT / REFRESH / CONSOLIDATE / PRUNE / REWORK-INTENT / TECHNICAL-ONLY) with a stated hypothesis and evidence IDs; cannibalization detection (same query, multiple URLs)
  • Randomized 30–40 % held-out control; weekly site-wide change cap enforced by cap.py
  • Decisions → W2/W5 cards; Opus only on ambiguous cases
  • Optionally rebuild the diagnostic half (SERP top-3 gap analysis) from the deleted prototype's design notes in memory — only after the evidence-ID contract is generalised

Phase F — Scale, research, citation (plan P5–P7 → parameterized C3, C8, W4, W6)

Pending

0/3 steps

Gate: only if D and E passed.

Steps
  • Parameterize create_page.py into build_family.py ("visa|IDP|passport family for [country set]") under cap.py + commercial gate
  • scripts/engine/research.py: source-watch events + SERP-shift detection as primary triggers → candidate briefs → admit_brief.py; keyword sweep secondary, low-frequency; idempotency rule vs in-flight W2 cards
  • Citation experiment: metric + baseline on the cohort, A/B on a subset, rich-result eligibility re-verified first

Waiting on decisions / inputs

Staged fixes (not applied to live)

Work log

2026-09-03Phase B step 3b–4 — host tiering, capture, source queue, truth gate (2026-09-03)complete
2026-09-03Progress tracker (2026-09-03)complete
2026-09-03Phase B step 3a2 — nationality pages + IDP routes (2026-09-03)complete (staged, not applied to live; committed + pushed 2026-09-03 after 2 review rounds)
2026-09-03Phase B step 3a — FIX-FACT convention statementscomplete (committed + pushed 2026-09-03; round-2 diff review clean)
2026-09-02Phase B: Truth layerin_progress
2026-09-02Phase A: Plan to v1.0complete

Recent commits (expedify repo)

a7ceabfb2026-09-03engine: Phase B step 3b-4 — host tiering, capture script, human source queue, truth gate
8466e6d62026-09-03engine: progress tracker generator (task_plan/progress/report/git → static page + status.json, wrangler deploy)
f3d4efd42026-09-03engine: corrected IDP routes copy + 19 idp_nationality pages staged from it (live untouched)
ee0973372026-09-03content: FIX-FACT convention statements on 24 pages (17 country hubs, 7 driving guides)
094a59652026-09-02engine: Phase B step 1-2 — facts schema v0.3, authority registry, read-only fact extractor
56674bff2026-09-02docs: sign AI Content Engine plan v1.0 — §9 numbers agreed, growth-cap ADR 0005
14e3a1ee2026-09-02docs: close plan v0.4 §8 decisions — ADRs 0001-0004, developer requests, PRD post-mortem
0ea1cc702026-09-02docs: client-facing AI Content Engine PRD, revised 2026-09-02 to plan v0.4
7f487c132026-09-02chore: ignore planning-with-files working memory
787647242026-09-02docs: AI Content Engine plan v0.4 — reconciled, plan-only
535a3ebe2026-08-31ad-campaign
99e8eede2026-08-31Merge pull request #2 from expedify-hk/fix/expedify-claims-corrections