Skip to content

feat(evidence): Phase 2b readiness gates + rebuild auto-regen flag - #54

Merged
xinhuagu merged 7 commits into
mainfrom
feat/phase2b-readiness-workflow
Jun 3, 2026
Merged

feat(evidence): Phase 2b readiness gates + rebuild auto-regen flag#54
xinhuagu merged 7 commits into
mainfrom
feat/phase2b-readiness-workflow

Conversation

@xinhuagu

@xinhuagu xinhuagu commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Operationalise the Phase 2b flip decision: the evidence report now publishes a phase2bReadiness verdict (ready / not-ready / insufficient-data) against three concrete numeric gates instead of leaving "once the would-reject ratio settles" as a vibe call.
  • Connect existing pieces — no new MCP tool, no new agent-visible field. The verdict lives in wiki_admin evidence-report output (operator-facing), and wiki_admin rebuild gains an opt-in evidence_report: true flag so the dashboard can stay fresh as part of a regular rebuild.
  • Document the gates and the flip workflow in docs/evidence-envelope.md so the numbers are explicit rather than implicit.

Gates

Gate Threshold Window
Total writes ≥ 50 last 4 weeks
Weekly wouldRejectRatio < 5% per week each of the last 4 weeks (weeks with 0 writes pass by default)
Search abstain ratio ≤ 30% last 30 days, requires ≥ 10 searches

Below-50-total flags as insufficient-data (statistically thin); a single bad week or a high search abstain rate flags as not-ready. Conservative on purpose — a false-positive ready would block legitimate writes.

When status: ready and currentlyEnabled: no, the rendered report includes the exact AGENT_WIKI_EVIDENCE_REJECT_UNSUPPORTED=true knob to flip.

Test plan

  • Unit tests for assessPhase2bReadiness cover: insufficient-data, ready, not-ready (weekly ratio), zero-write weeks passing by default, search-gate skipping under threshold, search-gate triggering above threshold, currentlyEnabled reflecting wiki config
  • Render tests cover: section appears in every report, per-week table rows with ✓/✗, flip-tip appears only when ready+not-enabled, flip-tip suppressed when already enabled
  • Server tests cover: wiki_admin --action rebuild evidence_report:true writes wiki/evidence-report.md and includes the Phase 2b section; rebuild without the flag leaves the file untouched
  • Full suite green: 55 files / 2159 tests pass

🤖 Generated with Claude Code

Operationalise "once the would-reject ratio settles" from
docs/evidence-envelope.md: instead of a vibe call, the evidence report
now publishes a Phase 2b readiness verdict against three numeric gates
(4-week total writes >= 50, every weekly wouldRejectRatio < 5%, search
abstain ratio <= 30% when >= 10 searches). Operators read the gates in
wiki/evidence-report.md and flip AGENT_WIKI_EVIDENCE_REJECT_UNSUPPORTED
when the report shows "READY".

Connects existing pieces - no new MCP tool, no new agent-visible field.
wiki_admin rebuild gains an opt-in `evidence_report: true` flag so the
dashboard can stay fresh without a separate evidence-report call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00c341cea0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/evidence-report.ts Outdated
lines.push(
`> All gates pass. To flip Phase 2b on, set ` +
`\`AGENT_WIKI_EVIDENCE_REJECT_UNSUPPORTED=true\` (env var) or ` +
`\`evidence.rejectUnsupportedWrites: true\` in \`.agent-wiki.yaml\`. ` +

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the parsed YAML key in flip instructions

When an operator follows this ready-state tip and adds evidence.rejectUnsupportedWrites: true to .agent-wiki.yaml, the config loader will ignore it: the YAML parser reads evidenceData.reject_unsupported_writes into wiki.config.evidence.rejectUnsupportedWrites (checked in src/wiki.ts), so only evidence.reject_unsupported_writes: true enables Phase 2b via YAML. This makes the report's primary non-env flip instruction ineffective exactly in the scenario where the gates say it is safe to enable.

Useful? React with 👍 / 👎.

xinhuagu and others added 3 commits June 3, 2026 22:26
High:
- Render tip and docs/evidence-envelope.md now name the correct YAML key
  evidence.reject_unsupported_writes (snake_case). The loader at
  wiki.ts:581 only reads the snake form; the camel form silently no-ops.
- Batch dedup now carries `evidence_report:true` through to the
  end-of-batch rebuild. Previously the flag was dropped along with the
  deduped wiki_admin op, so batch callers got no report despite ok:true.

Medium:
- Inline rebuild path surfaces evidence-report regen failures in the
  ok-message instead of swallowing them. The operator explicitly asked
  for the report; silent failure leaves them no signal.

Low / polish:
- "Currently enabled" line drops the env-var attribution (state can come
  from YAML too).
- Drop dead `applicable: true` literal from the two always-applicable
  gate shapes; keep the discriminant on searchAbstain.
- Un-export the four PHASE2B_* threshold constants; no external consumer.
- Rebuild handler's evidence_report flag uses `?? false` to match the
  surrounding boolean-coercion idiom.
- Anchor the per-week table regex to full-line shape so a regression on
  indent or trailing pipe would fail rather than silently match.

Tests:
- Regression test for the snake_case key in the rendered tip.
- Two batch tests covering evidence_report:true on/off through dedup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Medium:
- Extract `regenerateEvidenceReport` helper used by both the inline
  wiki_admin rebuild handler and the end-of-batch path. Batch now
  surfaces failure as a follow-up `wiki_admin warning` entry in
  `results` instead of swallowing it, matching the inline path's
  operator-requested contract. The misleading "mirrors the inline
  rebuild path's tolerance" comment is gone.
- Switch the Phase 2b flip-criteria link from `../docs/...` to an
  absolute GitHub URL. The relative path dead-links when
  wiki/evidence-report.md is written under a user-supplied wiki/ dir
  (docs/ does not ship in the npm package).

Low / polish:
- Align boolean coercion: inline rebuild path and wiki_evidence_report
  both now use `args.foo === true`, matching the batch sniff. Same
  flag, same semantics on every entry point.
- Decouple the Phase 2b gate window from `WEEKS_OF_TREND`. Introduce
  `PHASE2B_GATE_WEEKS = 4` and slice `trend.slice(-PHASE2B_GATE_WEEKS)`
  in `assessPhase2bReadiness` so widening the display sparkline later
  doesn't silently halve the gate threshold.
- Narrow failingWeeks via a typed predicate; drop the unreachable
  `(w.ratio ?? 0) * 100` defensiveness.

Tests:
- Render assertion that the flip tip uses the absolute GitHub URL and
  does not contain a relative `../docs/` path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Medium:
- Batch end-of-batch rebuild now runs `migrateExistingPagesForEvidence`
  alongside `rebuildIndex` + `rebuildTimeline`, mirroring the inline
  wiki_admin rebuild handler. Without it, a fresh batch-driven rebuild
  on a never-migrated wiki produced an evidence report that bucketed
  legacy pages as `other` instead of `legacyUnsupported`. Migration is
  marker-file-gated and one-shot, so the call is a no-op after the
  first run on any given workspace.
- Batch evidence-report failure now mutates the deferred result entry
  in place rather than pushing a sibling `{ tool, warning }` entry.
  The old shape (a) inflated `count: results.length` so callers iterating
  ops paired with results broke on failure, and (b) introduced a
  `warning` key absent elsewhere in `src/`. Operators get the regen
  status on the same op slot as the rebuild itself, in a uniform shape.

Low / polish:
- User-visible "4 weeks" strings (the reason text and the per-window
  gate label) interpolate `PHASE2B_GATE_WEEKS` instead of a hardcoded
  literal — matches the precedent set by `Trend (last ${WEEKS_OF_TREND}
  weeks)` and survives any future re-calibration.
- Move the orphan JSDoc block from above `PHASE2B_GATE_WEEKS` to attach
  to `export interface Phase2bReadiness`, where it documents the actual
  public surface. The constant keeps its own focused docblock.

Tests:
- Batch test asserts the 1-op→1-result invariant explicitly (count, length,
  and the deferred entry shape).
- New batch test asserts `.agent-wiki/evidence-migrated` marker exists
  after batch rebuild, pinning the migration step against future drift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2fc63b085

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/evidence-report.ts
};

const perWeek = gateBuckets.map((b) => {
const ratio = b.totalWrites === 0 ? null : b.unsupportedOrRejected / b.totalWrites;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Count legacy edits in the would-reject gate

When a corpus still has migrated legacyUnsupported pages being edited, warn-mode writes are logged as kind: "legacy" (src/wiki.ts:1554), and the Phase 2b path rejects the same updates (src/wiki.ts:1514). This readiness gate divides only unsupportedOrRejected by total writes, so 50+ legacy edits with no fresh unsupported writes can report READY even though enabling Phase 2b would block those edits. Please include legacy writes in the numerator or add a separate gate for unresolved legacy edit volume.

Useful? React with 👍 / 👎.

Medium:
- Extract `runPostRebuildEvidence(wiki, { regenerateReport })` as the
  single source of truth for migration + weekly log digest + optional
  evidence-report regen. Both `wiki_admin action:rebuild` (inline) and
  the end-of-batch rebuild now call it, eliminating the copy-paste
  pattern that produced previous parity bugs (missing weekly log
  digest in batch). Adding a new step now lands in one place.
- Inline rebuild emits a structured `evidenceReport: { ok: false,
  error }` field alongside `ok: true` when regen fails — programmatic
  callers can detect partial-success without sniffing `message`.
  Matches the batch path's deferred-entry mutation shape.

Low / polish:
- Revert booleans in `wiki_evidence_report.write`, inline rebuild's
  `evidence_report`, and the batch sniff to the `(args.X as boolean)
  ?? false` convention used by sibling booleans (`apply_fixes`, etc).
  The strict `=== true` check was an over-correction that introduced
  an undocumented behavior change on `wiki_evidence_report.write`.
- `runEvidenceReport` gains overloads so `write: true` narrows
  `writtenTo` to `string`. `regenerateEvidenceReport` drops the
  unreachable `?? "wiki/evidence-report.md"` fallback.
- Add `pickGateBuckets` helper that throws when `PHASE2B_GATE_WEEKS
  > trend.length` — surfaces a calibration mismatch (e.g. someone
  raising the gate window without widening `WEEKS_OF_TREND`) instead
  of silently making the min-writes gate easier to pass.
- Replace the bespoke `FailingWeek` type guard with a plain filter +
  `w.ratio!` at the use site. The invariant (`!passing → ratio !==
  null`) is documented in a comment; a discriminated-union refactor
  isn't worth it for two lines.
- Lift the flip-criteria URL to a module-level `FLIP_CRITERIA_URL`
  constant so a repo rename or fork updates one literal. The previous
  comment claimed `docs/` doesn't ship in the npm package, which is
  factually wrong (`package.json#files` lists it) — replaced with the
  real reason (wiki dir's position relative to docs/ is not stable).

Tests:
- Pin: inline rebuild with evidence_report:true emits no
  `evidenceReport` field on success — the field appears only on
  failure (parity with the batch path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6204aa98ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server.ts
Comment on lines +3247 to +3249
const bookkeeping = runPostRebuildEvidence(wiki, {
regenerateReport: needsEvidenceReport,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid migrating ordinary batch writes

When a workspace has no .agent-wiki/evidence-migrated marker, any batch containing wiki_write now reaches this helper because wiki_write sets needsRebuild; the helper runs migrateExistingPagesForEvidence, whose rule 4 clears unsupported: true and replaces it with legacyUnsupported: true for pages without sources. That means the first unsupported page created via a batch is immediately grandfathered as legacy instead of remaining a fresh unsupported write, so source coverage/read downgrades no longer reflect what the user just wrote. Limit the migration helper to explicit rebuild ops or run migration before processing batch writes.

Useful? React with 👍 / 👎.

Low:
- Inline `trend.slice(-PHASE2B_GATE_WEEKS)` at its single call site
  and drop the `pickGateBuckets` helper. Both constants live in the
  same file, both equal 4, and `aggregateTrend` deterministically
  returns exactly `WEEKS_OF_TREND` buckets — the throw was unreachable.
  Keep a 1-line guard adjacent to the slice so a future calibration
  bump still fails loud instead of silently making the gate easier.
- Drop the `runEvidenceReport` overload pair. Only beneficiary was
  `regenerateEvidenceReport`; the cost was `wiki_evidence_report`
  paying a runtime-meaningless ternary purely to satisfy overload
  resolution, and the narrowed `writtenTo` was JSON-stringified
  either way. `regenerateEvidenceReport` now null-checks at the use
  site; the wiki_evidence_report call collapses to a single
  `runEvidenceReport(wiki, { write })`.
- Add `await new Promise((r) => setImmediate(r))` between
  `rebuildIndex` and `rebuildTimeline` in the batch end-of-batch
  rebuild. Mirrors the inline path (commit 764c2fe rationale: slow
  filesystems like OneDrive-synced workspaces) so the MCP transport
  can answer client pings during long batched rebuilds — direct
  parity that the round-3 commit message claimed but missed.
- `evidence-report.test.ts` saves/clears `AGENT_WIKI_EVIDENCE_REJECT
  _UNSUPPORTED` in `beforeEach`/`afterEach` so a developer running
  tests with the env var set (a scenario this PR explicitly
  documents) doesn't see the `currentlyEnabled: false` assertion
  fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 063d1867c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/evidence-report.ts
Comment on lines +199 to +203
const totalWritesValue = gateBuckets.reduce((acc, b) => acc + b.totalWrites, 0);
const totalWritesGate = {
value: totalWritesValue,
threshold: PHASE2B_MIN_TOTAL_WRITES,
passing: totalWritesValue >= PHASE2B_MIN_TOTAL_WRITES,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude internal writes from readiness volume

When code-generated pages are produced by code_parse or wiki_admin rebuild, they are written through wiki.write as well (for example src/server.ts:2462, src/server.ts:2473, and src/server.ts:2581), and the counter has no source filter, so these generated grounded/synthesis writes are included in gateBuckets. In COBOL-heavy workspaces, repeated parses/rebuilds can therefore satisfy the ≥50-write gate and keep the ratio low with little or no actual wiki_write activity, causing the Phase 2b report to show READY even though the sample did not measure user/agent unsupported-write behavior.

Useful? React with 👍 / 👎.

Round-6 review caught a JSDoc on PHASE2B_GATE_WEEKS still pointing at
the pickGateBuckets helper that was inlined in round 5. Rewrite to
reference the actual enforcement site (the inline trend.length guard
in assessPhase2bReadiness).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xinhuagu
xinhuagu merged commit 1d6acdb into main Jun 3, 2026
2 checks passed
@xinhuagu
xinhuagu deleted the feat/phase2b-readiness-workflow branch June 3, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant