Skip to content

feat: ChittyTriage + ChittyRoux carry-through - #104

Merged
chitcommit merged 16 commits into
mainfrom
feat/chittytriage-roux
Jun 4, 2026
Merged

chitcommit merged 16 commits into
mainfrom
feat/chittytriage-roux

Conversation

@chitcommit

@chitcommit chitcommit commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Carries through ChittyTriage queue + ChittyRoux classification axes
(privilege, space) on cc_intents and cc_disputes.

Stacked PR. Base = fix/codex-p2-comments (PR #103), which depends on
PR #101. Merge order: #101#103 → this PR.

Ratified decisions (chittycanon-code-cardinal)

Q Decision Notes
Q1 — where do axes live? (c) First-class columns on cc_intents AND cc_disputes, with composite indexes on (axis, status). CHECK deferred (Roux spec is STATUS:PENDING). Enforced in app layer for now.
Q2 — legacy rows? (a) Pass-through-with-warn. Columns default to public/business; pushUnlinkedDisputesToNotion emits a one-time per-row log when it sees those defaults. No backfill writes.
Q3 — claim semantics? Both modes. Specific-by-ID (POST /api/triage/:id/claim, 409 if not pending) for humans, bucket-ordered (POST /api/triage/claim-next) for autonomous agents. MCP-exposed as four tools.
Q4 — vocab vs. sovereignty? Orthogonal. privilege ∈ {privileged, pii, hoa_evidentiary, public} is the Roux class. Pre-existing sensitivity ∈ {low, normal, sensitive, critical} is the trust-tier axis the sovereignty gate consumes. decide() is NOT modified.

Files changed (7 commits)

  1. migrations/0004_roux_privilege_space.sql + src/db/schema.ts — columns + indexes
  2. meta/intent.ts + meta/sovereignty.ts — types, createIntent, claimNextIntent filters, rowToIntent
  3. src/routes/triage.ts (new) + src/index.ts — mount /api/triage/*
  4. src/routes/mcp.ts — 4 new tools (triage_list_intents, triage_claim_intent, triage_claim_next, triage_complete_intent)
  5. src/lib/dispute-sync.tsderiveRouxFromType, Notion suppression gate, backfill warn
  6. docs/architecture/ADR-001-meta-orchestrator-extension.md — Delta section
  7. tests/routes/triage-roux.spec.ts + tests/lib/dispute-sync-roux.spec.ts — real-Neon integration tests

Notion mirror gate

linkDisputeToNotion returns false (suppression) when effective
privilege ∈ {privileged, pii} OR space === 'legalink'. Effective values
resolve as explicit > deriveRouxFromType(dispute_type). Mapping:

  • legal{privileged, legalink}
  • insurance{pii, business}
  • property | vendor | tenant | financial | unknown{public, business}

Neon validation

DDL validated on disposable branch br-broad-mud-ak4k790p of project
cool-bar-13270800 (parent br-weathered-hall-akoq1ily), against a
post-0003-codex-p2-fixes schema baseline:

ALTER TABLE cc_intents  ADD COLUMN privilege text NOT NULL DEFAULT 'public';   -- []
ALTER TABLE cc_intents  ADD COLUMN space     text NOT NULL DEFAULT 'business'; -- []
CREATE INDEX idx_cc_intents_privilege ON cc_intents(privilege, status);        -- []
CREATE INDEX idx_cc_intents_space     ON cc_intents(space, status);            -- []
ALTER TABLE cc_disputes ADD COLUMN privilege text NOT NULL DEFAULT 'public';   -- []
ALTER TABLE cc_disputes ADD COLUMN space     text NOT NULL DEFAULT 'business'; -- []
CREATE INDEX idx_cc_disputes_privilege ON cc_disputes(privilege, status);      -- []
CREATE INDEX idx_cc_disputes_space     ON cc_disputes(space, status);          -- []

Post-DDL verification:

column_name | data_type | column_default
------------+-----------+----------------
privilege   | text      | 'public'::text     (cc_disputes)
space       | text      | 'business'::text   (cc_disputes)
privilege   | text      | 'public'::text     (cc_intents)
space       | text      | 'business'::text   (cc_intents)

indexname
-------------------------
idx_cc_disputes_privilege
idx_cc_disputes_space
idx_cc_intents_privilege
idx_cc_intents_space

Null-passthrough cast pattern verified: SELECT (NULL::text IS NULL OR 'x' = NULL::text) → true.

Test plan

  • npm run typecheck — clean
  • Integration tests run with DATABASE_URL set against a Neon branch
  • Manual curl of GET /api/triage, POST /api/triage/:id/claim, POST /api/triage/claim-next, POST /api/triage/:id/complete post-deploy
  • MCP tools/list shows the four new triage_* entries
  • Verify a legal dispute does NOT mirror to Notion
  • Verify a property dispute DOES reach the Notion code path

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added triage queue system with endpoints to list, claim, and complete pending work items.
    • Introduced privilege and space classification for intents and disputes to support enhanced workflow organization.
    • Added autonomous agent support for claiming next eligible work via new priority-aware selection logic.
  • Documentation

    • Published architectural decision record defining governance-aligned triage handling and external mirroring policies.
  • Tests

    • Added integration test coverage for triage operations, privilege/space filtering, and claim atomicity.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d43e3048-6385-427d-a3cf-4646f05aec51

📥 Commits

Reviewing files that changed from the base of the PR and between d11f195 and 9da3df6.

📒 Files selected for processing (16)
  • docs/architecture/ADR-001-meta-orchestrator-extension.md
  • meta/intent.ts
  • meta/sovereignty.ts
  • migrations/0004_premium_toad_men.sql
  • migrations/meta/0004_snapshot.json
  • migrations/meta/_journal.json
  • src/db/schema.ts
  • src/index.ts
  • src/lib/dispute-sync.ts
  • src/middleware/auth.ts
  • src/routes/mcp.ts
  • src/routes/triage.ts
  • tests/lib/dispute-sync-roux.spec.ts
  • tests/mcp.test.ts
  • tests/meta/intent-lifecycle.spec.ts
  • tests/routes/triage-roux.spec.ts

📝 Walkthrough

Walkthrough

The PR implements the governance-ratified "Roux/Triage Carry-Through" feature, adding privilege and space classification dimensions to intents and disputes. It includes database migrations, updated data models, dispute-to-Notion gating rules, authorized HTTP and MCP APIs for managing pending intent queues, and comprehensive integration tests.

Changes

Roux/Triage Carry-Through Feature

Layer / File(s) Summary
Classification Types, Schema Migration, & Database Schema
meta/intent.ts, meta/sovereignty.ts, migrations/0004_premium_toad_men.sql, migrations/meta/_journal.json, src/db/schema.ts, docs/architecture/ADR-001-meta-orchestrator-extension.md
Introduces IntentPrivilege and IntentSpace exported types, adds privilege/space columns with defaults and indexes to both cc_intents and cc_disputes via SQL migration and schema definition, and documents governance rules in the ADR delta section.
Intent Data Model & Persistence
meta/intent.ts
Extends Intent and CreateIntentInput interfaces with optional privilege/space fields, implements createIntent to insert new classification columns with defaults (public/business), and updates rowToIntent mapping to read and default these dimensions.
Intent Dispatch Filtering & Completion Status Broadening
meta/intent.ts
Generalizes claimNextIntent to accept optional privilege, space, and priorityLte filters for bucket-ordered autonomous claiming, broadens completeIntent to accept claimed or running status for direct terminal transitions while preserving token gating.
Sovereignty Data Plane Information Field
meta/sovereignty.ts
Adds optional privilege field to IntentForSovereignty interface with documentation clarifying it is informational and not consumed by the decide() matrix.
Dispute-to-Roux Mapping & Notion Gating
src/lib/dispute-sync.ts
Exports deriveRouxFromType helper to deterministically map dispute_type to default privilege/space using "legal"/"insurance" heuristics, updates pushUnlinkedDisputesToNotion to detect legacy default cases and re-derive classification, and implements linkDisputeToNotion Roux gating that suppresses Notion creation when effective privilege is privileged/pii or space is legalink.
Triage Scope Authorization Middleware
src/middleware/auth.ts, src/index.ts
Introduces requireTriageScope middleware enforcing elevated scopes and hasTriageScope predicate helper, with app-level wiring to gate /api/triage/* routes.
Triage HTTP API Routes
src/routes/triage.ts, src/index.ts
Implements triageRoutes with GET /api/triage for listing pending intents with privilege/space filters, POST /api/triage/:id/claim for atomic direct claiming with scheduled-time cutoff, POST /api/triage/claim-next for autonomous bucket selection, and POST /api/triage/:id/complete for state transitions with outcome validation.
MCP Tool Registration & Execution
src/routes/mcp.ts
Registers four triage_* tools with input schemas, adds tools/list filtering to hide triage tools from unprivileged callers, enforces tools/call authorization checks, and implements executeTool handlers for intent listing, claiming (direct and bucket-ordered), and completion with outcome validation.
Intent Lifecycle & Token Gating Tests
tests/meta/intent-lifecycle.spec.ts
Extends test coverage with claimed→done transitions without intervening running state, token-gating enforcement while in claimed status preventing stale token completion, and reclaim/token race regression test.
Dispute-Roux Mapping & Gating Tests
tests/lib/dispute-sync-roux.spec.ts
Validates deriveRouxFromType dispute-type-to-privilege/space mapping with safe defaults, verifies linkDisputeToNotion suppresses Notion creation for suppressed combinations, and tests override precedence.
Triage Routes Integration Tests
tests/routes/triage-roux.spec.ts
Integration tests verifying privilege/space round-tripping in intent CRUD, claimNextIntent filtering behavior, atomic claiming idempotency, and priority ordering within privilege/space buckets.
MCP Tools Count Assertion Update
tests/mcp.test.ts
Updates tools/list test to expect 54 tools (from 50) documenting the 4 added triage tools.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • chittyos/chittycommand#103: Adds dispatched-task token gating for completeIntent/failIntent in meta/intent.ts, which this PR extends with claimed-status handling while preserving token enforcement.
  • chittyos/chittycommand#26: Modifies src/lib/dispute-sync.ts around pushUnlinkedDisputesToNotion/linkDisputeToNotion dispute↔Notion integration, which this PR builds on by adding Roux privilege/space gating logic.

Poem

🐰 Hops through the schema with privilege and space,
Disputes now flow through Roux's embrace,
Triage queues claim with atomic grace,
Token-safe completion finds its place,
Sovereign intents carry forth the case!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chittytriage-roux

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
  1. @coderabbitai review
  2. @copilot review
  3. @codex review
  4. @claude review
    Adversarial review request: evaluate security, policy bypass paths, regression risk, and merge-gating bypass attempts.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 3, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
chittycommand 9da3df6 Jun 04 2026, 11:52 AM

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@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: cbae5da0c5

ℹ️ 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/lib/dispute-sync.ts
Comment thread src/routes/triage.ts Outdated
Comment thread migrations/0004_roux_privilege_space.sql Outdated
Comment thread src/routes/triage.ts
@chitcommit
chitcommit force-pushed the fix/codex-p2-comments branch from 1258ac1 to 5ce549f Compare June 3, 2026 22:46
@chitcommit
chitcommit force-pushed the feat/chittytriage-roux branch from cbae5da to f3e9ec6 Compare June 3, 2026 22:47
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
  1. @coderabbitai review
  2. @copilot review
  3. @codex review
  4. @claude review
    Adversarial review request: evaluate security, policy bypass paths, regression risk, and merge-gating bypass attempts.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@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: f3e9ec6621

ℹ️ 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/routes/triage.ts Outdated
Comment thread src/lib/dispute-sync.ts Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
  1. @coderabbitai review
  2. @copilot review
  3. @codex review
  4. @claude review
    Adversarial review request: evaluate security, policy bypass paths, regression risk, and merge-gating bypass attempts.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

Base automatically changed from fix/codex-p2-comments to main June 4, 2026 02:09
chitcommit and others added 9 commits June 4, 2026 02:11
Migration 0004 adds privilege ∈ {privileged,pii,hoa_evidentiary,public} and
space ∈ {business,legalink} as first-class text columns on cc_intents and
cc_disputes, with composite indexes on (axis, status). CHECK constraints are
deferred — the Roux spec URI is STATUS:PENDING and enum is enforced in the
app layer.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

Validated on Neon branch br-broad-mud-ak4k790p of project cool-bar-13270800:
ADD COLUMN + CREATE INDEX succeed on top of the post-0003 schema; defaults
applied to existing rows.

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

- Intent interface gains privilege/space (typed unions, sourced from canon).
- CreateIntentInput accepts optional privilege/space; INSERT defaults to
  public/business when caller omits.
- claimNextIntent grows null-passthrough filters for privilege, space, and
  priority_lte so a single prepared statement covers the autonomous-bucket
  and human-channel paths.
- rowToIntent maps the new columns.
- sovereignty.ts: add optional privilege field to IntentForSovereignty for
  audit-trail persistence. decide() is intentionally NOT modified — privilege
  is orthogonal to the trust-tier sensitivity axis the gate consumes.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GET  /api/triage              — list pending intents, filter by privilege/space
POST /api/triage/:id/claim    — atomic claim-by-ID, 409 if not pending
POST /api/triage/claim-next   — bucket-ordered claim for autonomous agents
POST /api/triage/:id/complete — terminal transition (done|failed) with the
                                same status guards used in meta/intent.ts

Mounted after /api/tasks; covered by the existing global /api/* authMiddleware.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- triage_list_intents({privilege?, space?, limit?})
- triage_claim_intent({id})
- triage_claim_next({privilege?, space?, priority_lte?})
- triage_complete_intent({id, outcome, error?})

Each tool wraps the matching /api/triage route's semantics so Claude Code
sessions can drive the queue without HTTP plumbing. Validation reuses the
ratified privilege/space enums from meta/intent.ts.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

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

- deriveRouxFromType(disputeType) maps dispute_type → ratified Roux defaults:
    'legal'      ⇒ {privilege:'privileged', space:'legalink'}
    'insurance'  ⇒ {privilege:'pii',        space:'business'}
    others       ⇒ {privilege:'public',     space:'business'}
- linkDisputeToNotion now gates: if effective privilege ∈ {privileged, pii}
  OR space = 'legalink', the function logs the suppression and returns false
  before touching Notion. Effective values resolve as explicit > derived.
- pushUnlinkedDisputesToNotion now SELECTs privilege/space and emits a
  per-row warn when the row sits on the migration defaults — surfaces
  legacy untagged disputes for explicit triage (Q2=(a) pass-through-warn).
- linkDisputeToNotion is now exported for direct integration testing.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Records the four ratified decisions from chittycanon-code-cardinal:

  Q1 — privilege+space land as first-class columns on cc_intents AND
       cc_disputes; CHECK deferred until Roux spec is CERTIFIED.
  Q2 — pass-through-with-warn on legacy rows (column defaults).
  Q3 — both specific-by-ID and bucket-ordered claim modes.
  Q4 — privilege is orthogonal to sensitivity; decide() is untouched.

Also documents the Notion mirror gate and explicit > derived resolution.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tests/routes/triage-roux.spec.ts
  - createIntent privilege+space round-trip
  - claimNextIntent honors bucket filter (won't grab a higher-priority intent
    in the wrong bucket)
  - second atomic claim of the same intent returns 0 rows (the 409 source)
  - bucket-scoped claim still respects priority within the bucket

tests/lib/dispute-sync-roux.spec.ts
  - deriveRouxFromType: legal/insurance/property/vendor + unknown safe default
  - linkDisputeToNotion suppresses on explicit privilege=privileged
  - linkDisputeToNotion suppresses on explicit space=legalink
  - linkDisputeToNotion suppresses 'legal' via derived defaults
  - explicit (public, business) override beats derived (privileged, legalink)
    for a 'legal' dispute_type — gate passes (Notion call then no-ops in test)

Skip pattern mirrors tests/meta/intent-lifecycle.spec.ts — disabled without
DATABASE_URL or with SKIP_INTEGRATION=1.

@canon: chittycanon://gov/governance#classification-axes  STATUS:PENDING

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

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

Hand-written 0004_roux_privilege_space.sql was on disk but never registered
in migrations/meta/_journal.json, so drizzle-kit migrate would silently skip
it. Regenerated via `drizzle-kit generate` after rebasing onto the merged
PR #103 baseline; auto-named 0004_premium_toad_men.sql now carries the
same 4 ALTER COLUMN + 4 CREATE INDEX statements (cc_intents/cc_disputes
privilege+space + composite indexes) and is properly journaled with a
matching meta/0004_snapshot.json.

Validated on disposable Neon branch br-green-mode-akxyxiz5 of project
cool-bar-13270800: 0002 + 0003 + 0004 sequence applied cleanly; all 4
columns and 4 indexes verified via information_schema and pg_indexes.

Rebase also dropped 5 commits (f4cb131, 7027daa, 117d77d, 001e157,
5ce549f) that were the pre-squash form of merged PR #103.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chitcommit
chitcommit force-pushed the feat/chittytriage-roux branch from e0bd689 to 395af7a Compare June 4, 2026 02:14
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
  1. @coderabbitai review
  2. @copilot review
  3. @codex review
  4. @claude review
    Adversarial review request: evaluate security, policy bypass paths, regression risk, and merge-gating bypass attempts.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

chitcommit and others added 4 commits June 4, 2026 02:17
…fill

Finding 6 (P1): deriveRouxFromType only matched exact strings, so free-text
dispute_type values like "Legal" or "legal dispute" fell through to the
default public/business mapping and leaked into the Notion business bucket.
Lowercase + trim, then route any string containing "legal" to
privileged/legalink and any containing "insurance" to pii/business. This is
intentionally over-broad on the privileged side as a fail-safe.

Finding 1 (P1): pushUnlinkedDisputesToNotion treated rows that landed on the
column defaults (public/business) as explicit values, so a row with
dispute_type='legal' but no explicit privilege/space was passed through the
gate. Now, when both axes sit on defaults, re-derive from dispute_type for
the gate decision (DB row is untouched — retag is a separate concern).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Finding 2 (P2): claim-next called parsePrivilege/parseSpace and treated null
as "no filter", so an unrecognized value (e.g. "pi" instead of "pii") would
silently fall through and claim the highest-priority pending intent from any
bucket — including privileged/legalink. Mirror the GET /api/triage pattern:
when a filter is provided but doesn't parse, return 400 with the valid enum.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Finding 5 (P2): list + claim-next correctly exclude future-scheduled intents,
but the direct claim path (POST /api/triage/:id/claim and the
triage_claim_intent MCP tool) only gated on status='pending'. A client with
the ID could short-circuit the schedule and claim tomorrow's intent today.
Add scheduled_for guard to both paths and distinguish 409 with the
scheduled_for value in the response for client UX.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Finding 4 (P2): the triage routes expose claim (pending→claimed) but no
explicit claimed→running transition, so an autonomous agent that did its
work and called complete always got 409. Extend completeIntent's WHERE to
accept status IN ('claimed', 'running'), matching failIntent's existing
guard. The P1-B execution-token gate still rejects stale completions when a
token is supplied — so concurrent leaders are still protected.

Update error messages in the HTTP and MCP wrappers to reflect the relaxed
guard. Add three lifecycle tests: claimed→done, claimed→failed, and the
token-gate rejection on a claimed (not running) intent.

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

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
  1. @coderabbitai review
  2. @copilot review
  3. @codex review
  4. @claude review
    Adversarial review request: evaluate security, policy bypass paths, regression risk, and merge-gating bypass attempts.

@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: b3438e6932

ℹ️ 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 meta/intent.ts
Comment thread src/index.ts
Comment thread src/routes/mcp.ts
@chitcommit
chitcommit enabled auto-merge (squash) June 4, 2026 02:40
Mounting /api/triage under the generic authMiddleware let any valid
ChittyAuth user token list, claim, and complete privileged/legalink
intents. Add requireTriageScope middleware that runs after authMiddleware
and rejects callers without chittytriage:write, chittytriage:admin,
admin, or wildcard scope.

Also exports hasTriageScope() for reuse by the MCP dispatcher (next
commit) since that path runs inside JSON-RPC, not Hono middleware.

fixes codex-p2 PR#104 P1 — elevated scope on triage routes
The 4 triage_* MCP tools were reachable by any caller accepted by
mcpAuthMiddleware with the broad 'mcp' scope or the legacy KV shared
service token. That lets generic MCP integrations enumerate and mutate
privileged/legalink orchestration intents.

Two layers:
 - tools/list now filters triage_* tools out of the catalog unless the
   caller has chittytriage:write (don't advertise what they can't call).
 - tools/call enforces the same scope as a defense-in-depth gate so a
   caller that knows the tool name can't bypass the list filter.

Uses hasTriageScope() helper exported from src/middleware/auth.ts.

fixes codex-p2 PR#104 P1 — elevated scope on triage MCP tools
Codex flagged a possible race where a stale client A could complete a
re-claimed intent owned by client B with token A. After audit, the
existing token gate from PR#103 P1-B already prevents this:

  meta/intent.ts:332-337,367-373 — completeIntent/failIntent UPDATE
  predicate is `status IN ('claimed','running') AND dispatched_task_id
  = $expectedDispatchedTaskId`, covering BOTH claimed and running.

  meta/intent.ts:402 — reclaimStuckIntents sets dispatched_task_id =
  NULL when resetting to pending, so any subsequent re-claim writes a
  fresh token and the stale A token can never match.

Add a regression test that drives the exact race the reviewer
described (claim with tokenA → updated_at past reclaim window →
reclaimStuckIntents → re-claim with tokenB → tokenA tries complete +
fail) and asserts the row stays B's. No production-code change.

fixes codex-p2 PR#104 P2 — pin reclaim claim-token race
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
  1. @coderabbitai review
  2. @copilot review
  3. @codex review
  4. @claude review
    Adversarial review request: evaluate security, policy bypass paths, regression risk, and merge-gating bypass attempts.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chitcommit
chitcommit merged commit 7add490 into main Jun 4, 2026
14 of 17 checks passed
@chitcommit
chitcommit deleted the feat/chittytriage-roux branch June 4, 2026 11:52

@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: 9da3df616a

ℹ️ 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/middleware/auth.ts
export function hasTriageScope(scopes: string[] | undefined | null): boolean {
if (!scopes) return false;
return scopes.some(
(s) => s === 'chittytriage:write' || s === 'chittytriage:admin' || s === 'admin' || s === '*',

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 Grant triage scope during dev MCP bypass

When ENVIRONMENT !== 'production', mcpAuthMiddleware bypasses auth by setting scopes to ['mcp'], but this new allowlist does not treat that dev scope as elevated. As a result, local/test MCP clients cannot see or call any of the four triage tools even though dev auth is documented as bypassed; I verified npm test -- tests/mcp.test.ts now returns 50 tools instead of the updated expectation of 54. Either assign a triage scope in the dev bypass or make this helper aware of the non-production MCP scope.

Useful? React with 👍 / 👎.

chitcommit added a commit that referenced this pull request Jun 4, 2026
…113)

PR #104 round-3 (commit aa2f2d0) added scope-based filtering of triage_*
MCP tools from tools/list when the caller lacks chittytriage:write. The
test environment uses the mcpAuthMiddleware dev bypass which grants only
scope ['mcp'], so the 4 triage tools are filtered out and tools.length
is 50, not 54. The unconditional `expect(tools.length).toBe(54)` was
failing on main and blocking PR #112's CI build.

This commit:
- Renames the existing assertion to "exposes 50 tools to unscoped
  callers (triage tools hidden)" and adds explicit assertions that the
  4 triage_* tools are absent from the catalog.
- Adds a second test "exposes all 54 tools to callers with triage
  scope" that injects scopes=['chittytriage:write'] directly via a
  custom middleware (the dev bypass cannot grant triage scope, and the
  production code path would require mocking ChittyAuth fetch — direct
  scope injection is the deterministic way to exercise the scoped
  branch of tools/list).

Covers both code paths: hidden when unscoped, visible when scoped.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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