← back to AbramsOS

lib/openclaw-claim-filler.js

72 lines

// lib/openclaw-claim-filler.js — build an openclaw (real-Chrome portal-driver) job brief for a
// settlement claim Steve has marked ELIGIBLE. It PREFILLS his known identity into the claim form
// and STOPS at the penalty-of-perjury attestation + Submit button. It NEVER submits, and it is
// only ever called for eligibility_state='eligible' rows.
//
// The brief is dropped into two places:
//   • data/claim-fill-queue/<claim>.json   (app-local queue the dashboard reads)
//   • ~/.claude/yolo-queue/pending-approval/  (so a Claude/portal-driver session picks it up)
// The actual browser drive + the final human Submit happen via the portal-driver skill with Steve.
const fs = require('fs');
const path = require('path');
const os = require('os');

const LOCAL_Q = path.join(__dirname, '..', 'data', 'claim-fill-queue');
const APPROVAL_Q = path.join(os.homedir(), '.claude', 'yolo-queue', 'pending-approval');

// Hard guardrails copied into every brief so whoever/whatever runs it cannot miss them.
const GUARDRAILS = [
  'DO NOT click the final Submit / File Claim button. Stop at the review/attestation screen.',
  'DO NOT check any "I declare under penalty of perjury / I certify" box — that is Steve\'s to check.',
  'DO NOT invent, guess, or embellish eligibility facts (purchase, breach notice, employment, stock lot).',
  'If the form asks for proof Steve has not supplied, stop and report what is missing.',
  'Capture a screenshot of the fully-prefilled review screen and save its path in the result.',
];

function buildBrief(claim, profile) {
  return {
    kind: 'settlement-claim-fill',
    generated_at: new Date().toISOString(),
    claim: {
      id: claim.id, name: claim.name, slug: claim.slug,
      mode_url: claim.mode_url, admin_url: claim.admin_url || null,
      payout_text: claim.payout_text, deadline: claim.deadline,
      eligibility_question: claim.eligibility_question,
    },
    // Identity the agent MAY type into the form (from AbramsOS profile — never fabricated).
    prefill: {
      full_name: profile.full_name || null,
      email: profile.email || null,
      phone: profile.phone || null,
      address: profile.address || null,
    },
    steps: [
      `Open ${claim.mode_url || '(mode landing page)'} and follow through to the OFFICIAL settlement administrator's claim site.`,
      'Locate the online claim form. If the settlement is "no claim required / automatic", STOP — nothing to file; just verify the mailing address is current.',
      'Fill the form using ONLY the prefill identity above plus facts Steve has explicitly confirmed.',
      'Choose the "no proof required" / flat cash option when eligible and available.',
      'Advance to the final review screen, screenshot it, and STOP for Steve to attest + submit.',
    ],
    guardrails: GUARDRAILS,
    engine: 'openclaw-real-chrome',
    fill_state_on_success: 'prefilled_awaiting_submit',
  };
}

function stage(claim, profile) {
  if (claim.eligibility_state && claim.eligibility_state !== 'eligible') {
    throw new Error(`refusing to stage fill for non-eligible claim (state=${claim.eligibility_state})`);
  }
  const brief = buildBrief(claim, profile || {});
  fs.mkdirSync(LOCAL_Q, { recursive: true });
  const local = path.join(LOCAL_Q, `${claim.id}.json`);
  fs.writeFileSync(local, JSON.stringify(brief, null, 2));
  try {
    fs.mkdirSync(APPROVAL_Q, { recursive: true });
    fs.writeFileSync(path.join(APPROVAL_Q, `settlement-claim-${claim.slug}.json`), JSON.stringify(brief, null, 2));
  } catch (_e) { /* approval queue optional */ }
  return { brief, local };
}

module.exports = { buildBrief, stage, GUARDRAILS, LOCAL_Q };