◐ Off-By-One · answer catalog

typescript-stale-premise-task-closure

2 answer(s)godockergodocker

typescript-stale-premise-task-closure

📦 Source in repository (JSON)

Answer 1

The fix is a pre-dispatch verification gate for the P3 board, shipped as a small TypeScript CLI (~/stale-premise-closer/). Every open P3 row is a premise ("GET /api/v1/parents/{id}/analytics returns 403"); before spending a worker, it verifies the premise cheaply and closes dead rows with disposition + evidence. Three gates:

Gate 1 — consumer grep before believing "missing endpoint" rows (kills the BUG-LUNA-009 class). Zero frontend call sites → BY-DESIGN, close. Consumers exist → stay open, worker gets call-site evidence. Template-literal aware (/api/v1/profile/${id} matches /api/v1/profile/{id}):

// src/consumers.ts
export async function findConsumers(root: string, endpoint: string, maxResults = 10): Promise<ConsumerRef[]> {
  const out: ConsumerRef[] = [];
  if (!endpoint) return out;
  await walk(path.resolve(root), endpointToConsumerRegex(endpoint), out, maxResults);
  return out;
}
// param segments become wildcards: /api/v1/profile/{id}  ->  /api/v1/profile/[^\s`"']+/

Gate 2 — cheap live probe (kills the BUG-LUNA-010 class). One status-only GET with a hard timeout; two caller classes: anon (foreign/unauth) and authed (legit first-party, via --service-token):

// src/probe.ts
export async function probe(url: string, opts: ProbeOptions = {}): Promise<ProbeResult> {
  const started = Date.now();
  try {
    const res = await fetch(url, {
      method: 'GET', redirect: 'follow',
      headers: { 'user-agent': 'stale-premise-closer/1.0 (probe)', ...opts.headers },
      signal: AbortSignal.timeout(opts.timeoutMs ?? 4_000),
    });
    return { status: res.status, finalUrl: res.url, redirected: res.redirected, latencyMs: Date.now() - started };
    // body intentionally never read — a few ms of traffic, not a worker dispatch
  } catch (err) { /* status: null => timeout/DNS/refused */ }
}

Gate 3 — classify + close with evidence (src/classify.ts). Decision table: authed 2xx → RESOLVED-by-fix; correct access-control 4xx on a foreign resource (probe-expect: denied) → BY-DESIGN; any other 4xx/5xx, conflicting signals, or probe failure → STILL-OPEN/INCONCLUSIVE, never auto-closed. Orchestrated in src/closer.ts:

if (verdict.disposition === 'RESOLVED-by-fix' || verdict.disposition === 'BY-DESIGN') {
  if (!deps.opts.dryRun) {
    await deps.board.comment(row, verdict); // disposition + reason + evidence on the issue
    await deps.board.close(row, verdict);
  }
}

Rows can carry directives to keep them machine-verifiable: probe-url: (exact URL) and probe-expect: allowed|denied. --min-age-days refuses to auto-close rows touched recently. Boards: live GitHub issues (GithubBoard) or an offline JSON dump (JsonBoard); default is dry-run until --close.

node dist/cli.js --repo acme/api --token $GH_TOKEN --probe-base https://api.example.com \
  --service-token $SVC_TOKEN --frontend ../web --min-age-days 2 --close

Evidence & signatures

**36/36 tests pass** (`npm test`, strict `tsc --noEmit` clean), plus a live end-to-end demo:

- **BUG-LUNA-010 replay** — local API serves `/api/v1/parents/42/analytics` → 200 while the board row claims 403: row closed `RESOLVED-by-fix` with evidence `authed probe: 200 (2ms)`; board persisted `10:closed`. (Same flow: row with real 403 → `STILL-OPEN`, board unchanged.)
- **BUG-LUNA-009 replay** — "missing endpoint /api/v1/profile" row + frontend dir: zero consumers → `BY-DESIGN` closed; with a `fetch(`/api/v1/profile/${id}`)` consumer → `STILL-OPEN` kept.
- **Edge cases tested**: redirects followed to final 200; `followRedirects:false` returns raw 301; timeout (`AbortSignal.timeout`) → status null → `INCONCLUSIVE`; connection-refused → status null; authed-403 + anon-200 → `INCONCLUSIVE` (conflicting); authed 500 → `STILL-OPEN`; param substitution (`{parentId}` → probed as `/1`); dry-run computes verdicts but mutates nothing; min-age guard blocks fresh rows; `node_modules`/`.git` excluded from consumer grep; 401/403/404 treated as access control when `expect: denied`.
{"model": "deepseek-v4-flash", "problem_class": "typescript-stale-premise-task-closure", "result": "passed", "tests": 36}

Answer 2

The fix is a pre-dispatch verification gate for the P3 board, shipped as a small TypeScript CLI (~/stale-premise-closer/). Every open P3 row is a premise ("GET /api/v1/parents/{id}/analytics returns 403"); before spending a worker, it verifies the premise cheaply and closes dead rows with disposition + evidence. Three gates:

Gate 1 — consumer grep before believing "missing endpoint" rows (kills the BUG-LUNA-009 class). Zero frontend call sites → BY-DESIGN, close. Consumers exist → stay open, worker gets call-site evidence. Template-literal aware (/api/v1/profile/${id} matches /api/v1/profile/{id}):

// src/consumers.ts
export async function findConsumers(root: string, endpoint: string, maxResults = 10): Promise<ConsumerRef[]> {
  const out: ConsumerRef[] = [];
  if (!endpoint) return out;
  await walk(path.resolve(root), endpointToConsumerRegex(endpoint), out, maxResults);
  return out;
}
// param segments become wildcards: /api/v1/profile/{id}  ->  /api/v1/profile/[^\s`"']+/

Gate 2 — cheap live probe (kills the BUG-LUNA-010 class). One status-only GET with a hard timeout; two caller classes: anon (foreign/unauth) and authed (legit first-party, via --service-token):

// src/probe.ts
export async function probe(url: string, opts: ProbeOptions = {}): Promise<ProbeResult> {
  const started = Date.now();
  try {
    const res = await fetch(url, {
      method: 'GET', redirect: 'follow',
      headers: { 'user-agent': 'stale-premise-closer/1.0 (probe)', ...opts.headers },
      signal: AbortSignal.timeout(opts.timeoutMs ?? 4_000),
    });
    return { status: res.status, finalUrl: res.url, redirected: res.redirected, latencyMs: Date.now() - started };
    // body intentionally never read — a few ms of traffic, not a worker dispatch
  } catch (err) { /* status: null => timeout/DNS/refused */ }
}

Gate 3 — classify + close with evidence (src/classify.ts). Decision table: authed 2xx → RESOLVED-by-fix; correct access-control 4xx on a foreign resource (probe-expect: denied) → BY-DESIGN; any other 4xx/5xx, conflicting signals, or probe failure → STILL-OPEN/INCONCLUSIVE, never auto-closed. Orchestrated in src/closer.ts:

if (verdict.disposition === 'RESOLVED-by-fix' || verdict.disposition === 'BY-DESIGN') {
  if (!deps.opts.dryRun) {
    await deps.board.comment(row, verdict); // disposition + reason + evidence on the issue
    await deps.board.close(row, verdict);
  }
}

Rows can carry directives to keep them machine-verifiable: probe-url: (exact URL) and probe-expect: allowed|denied. --min-age-days refuses to auto-close rows touched recently. Boards: live GitHub issues (GithubBoard) or an offline JSON dump (JsonBoard); default is dry-run until --close.

node dist/cli.js --repo acme/api --token $GH_TOKEN --probe-base https://api.example.com \
  --service-token $SVC_TOKEN --frontend ../web --min-age-days 2 --close

Evidence & signatures

**36/36 tests pass** (`npm test`, strict `tsc --noEmit` clean), plus a live end-to-end demo:

- **BUG-LUNA-010 replay** — local API serves `/api/v1/parents/42/analytics` → 200 while the board row claims 403: row closed `RESOLVED-by-fix` with evidence `authed probe: 200 (2ms)`; board persisted `10:closed`. (Same flow: row with real 403 → `STILL-OPEN`, board unchanged.)
- **BUG-LUNA-009 replay** — "missing endpoint /api/v1/profile" row + frontend dir: zero consumers → `BY-DESIGN` closed; with a `fetch(`/api/v1/profile/${id}`)` consumer → `STILL-OPEN` kept.
- **Edge cases tested**: redirects followed to final 200; `followRedirects:false` returns raw 301; timeout (`AbortSignal.timeout`) → status null → `INCONCLUSIVE`; connection-refused → status null; authed-403 + anon-200 → `INCONCLUSIVE` (conflicting); authed 500 → `STILL-OPEN`; param substitution (`{parentId}` → probed as `/1`); dry-run computes verdicts but mutates nothing; min-age guard blocks fresh rows; `node_modules`/`.git` excluded from consumer grep; 401/403/404 treated as access control when `expect: denied`.
{"model": "deepseek-v4-flash", "problem_class": "typescript-stale-premise-task-closure", "result": "passed", "tests": 36}
Generated from the verified corpus · MIT licensedBack to the catalog