docs(ideate): v1.3 candidate ideas — codebase-drift ideation (12 candidates)

Source query: Gitea issue queue is now EMPTY (0 open issues).
The CTO has closed both INB-183 (paperclip monorepo PATH append,
rejected in v1.2) and INB-193 (the wrapper that the v1.3
research commit body had named as the v1.3 deliverable). The
v1.3 IDEATE pass is therefore driven entirely by codebase
analysis (per the user's redirect), not by the issue queue.

Tier 1 (mechanical, 8 findings → 8 REQs REQ-INB-28..35):
- T1-1 (P0): docs/gitea-actions.md:95 cto-inboxos drift
  (v1.1 P0 sweep missed this file; last touched Phase 4)
- T1-2 (P2): runbook footer "Next review" stale by 2 milestones
- T1-3 (P2): runbook §4.5 forward-pointer to v1.2 alerting
  (v1.2 never delivered alerting; pointer is stale)
- T1-4 (P2): papra-write-policy.md:192 test count 13→15
  (v1.1 added 2 tests; doc was not updated)
- T1-5 (P2): extraction-contract.md 4 stale line refs
  in pipelines/common.py
- T1-6 (P2): .env.example missing 7 workflow env vars
  (OLLAMA_API_KEY, INBOXOS_LLM_BACKEND, PAPRA_DRY_RUN,
   PAPRA_BODY_WRITE_MODULES, PAPRA_METADATA_ONLY_MODULES,
   MBOX_BUCKET, OPENCODE_NPM_VERSION)
- T1-7 (P0): 6 v1.1 offline tests not wired into ci-pr
  merge gate (papra_decide, papra_index, papra_link_parity,
  metrics, restore, rotate_secrets)
- T1-8 (XS): .gitignore opencode.json shadows tracked file
  (defer to v1.4)

Tier 2 (backend-enriched, v1.1 backlog + PIT items, 4 REQs):
- T2-1 (v1.1 P1-1): runbook §6 ordering 6.1→6.4→6.2→6.3
  → REQ-INB-36
- T2-2 (v1.1 P1-2): setup_gitea_secrets.sh cto-inboxos drift
  → REQ-INB-37
- T2-3 (v1.1 P2-1): apply_schemas.py --check papra_index test
  → REQ-INB-38 (DEFER, low value)
- T2-4 (v1.1 P2-2): test_papra_link_parity imapclient shim
  → REQ-INB-39 (DEFER, accepted-precedent disposition)

Tier 2 PIT items (3 carry-forward from v1.3 research):
- PIT-V1.3-1 (secret-scan pattern) → §10 lessons
- PIT-V1.3-2 (.ciagent/ sovereignty) → §10 lessons
- PIT-V1.3-3 (CI lint wiring) → absorbed into REQ-INB-34

Tier 2 re-verifications (3, drift-free at v1.3):
- T2-8: schemas.md ↔ apply_schemas.py column lists match
- T2-9: gemma4:e4b pin consistent across 5 prompts + .env.example
- T2-10: opencode backend dead code is intentional + documented

Tier 3 (cross-project, 0 REQ):
- CP-1: paperclip not a registered CIAgent project (carry)
- CP-2: inboxos source has 0 paperclip references (re-verify)
- CP-3: /root/workspace/paperclip/ unmodified (re-verify)

Disposition:
- 9 ACCEPT: REQ-INB-28, 29, 30, 31, 32, 33, 34, 36, 37
- 3 DEFER: REQ-INB-35, 38, 39
- 0 REJECT

Accept ratio: 9/12 (75%). No NocoDB schema impact. v1.3 is
doc-hygiene + test-wiring + env-file-drift + cto-inboxos
closure. Closes 2 v1.1 backlog items (P1-1, P1-2). Re-verifies
5 v1.0/v1.1 drift closures (model pin, schema, opencode dead
code, paperclip sovereignty).

---ci---
project: inboxos
phase: 1
milestone: v1.3
status: ideate
disposition:
  accepted: [REQ-INB-28, REQ-INB-29, REQ-INB-30, REQ-INB-31, REQ-INB-32, REQ-INB-33, REQ-INB-34, REQ-INB-36, REQ-INB-37]
  deferred: [REQ-INB-35, REQ-INB-38, REQ-INB-39]
  rejected: []
tier1:
  - id: T1-1
    finding: "docs/gitea-actions.md:95 cto-inboxos drift (v1.1 P0 sweep missed this file)"
    candidate: REQ-INB-28
    confidence: 0.90
    effort: XS
    schema_impact: no
    disposition: ACCEPT
  - id: T1-2
    finding: "runbook footer 'Next review' stale by 2 milestones"
    candidate: REQ-INB-29
    confidence: 0.95
    effort: XS
    schema_impact: no
    disposition: ACCEPT
  - id: T1-3
    finding: "runbook §4.5 forward-pointer v1.2 alerting stale"
    candidate: REQ-INB-30
    confidence: 0.80
    effort: XS
    schema_impact: no
    disposition: ACCEPT
  - id: T1-4
    finding: "papra-write-policy.md:192 test count 13→15"
    candidate: REQ-INB-31
    confidence: 0.90
    effort: XS
    schema_impact: no
    disposition: ACCEPT
  - id: T1-5
    finding: "extraction-contract.md 4 stale line refs"
    candidate: REQ-INB-32
    confidence: 0.85
    effort: S
    schema_impact: no
    disposition: ACCEPT
  - id: T1-6
    finding: ".env.example missing 7 workflow env vars"
    candidate: REQ-INB-33
    confidence: 0.80
    effort: S
    schema_impact: no
    disposition: ACCEPT
  - id: T1-7
    finding: "6 v1.1 offline tests not wired into ci-pr merge gate"
    candidate: REQ-INB-34
    confidence: 0.90
    effort: S
    schema_impact: no
    disposition: ACCEPT
    absorbs: [PIT-V1.3-3]
  - id: T1-8
    finding: ".gitignore opencode.json shadows tracked file"
    candidate: REQ-INB-35
    confidence: 0.65
    effort: XS
    schema_impact: no
    disposition: DEFER
tier2:
  - id: T2-1
    finding: "runbook §6 ordering non-monotonic (v1.1 P1-1)"
    candidate: REQ-INB-36
    confidence: 0.95
    effort: XS
    schema_impact: no
    disposition: ACCEPT
  - id: T2-2
    finding: "setup_gitea_secrets.sh cto-inboxos drift (v1.1 P1-2)"
    candidate: REQ-INB-37
    confidence: 0.90
    effort: XS
    schema_impact: no
    disposition: ACCEPT
  - id: T2-3
    finding: "apply_schemas.py --check papra_index offline test (v1.1 P2-1)"
    candidate: REQ-INB-38
    confidence: 0.85
    effort: XS
    schema_impact: no
    disposition: DEFER
    reason: "low value (runtime path covered by test_papra_index_offline.py); defer to v1.4"
  - id: T2-4
    finding: "test_papra_link_parity imapclient runtime shim (v1.1 P2-2)"
    candidate: REQ-INB-39
    confidence: 0.55
    effort: S
    schema_impact: no
    disposition: DEFER
    reason: "accepted-precedent disposition (v1.0 + v1.1 deferred-runtime); defer to v1.4"
tier2_re_verify:
  - id: T2-8
    finding: "schemas.md ↔ apply_schemas.py drift-free at column-list level"
    disposition: RE_VERIFY
  - id: T2-9
    finding: "gemma4:e4b pin consistent across 5 prompts + .env.example + opencode.json"
    disposition: RE_VERIFY
  - id: T2-10
    finding: "opencode backend dead code is intentional + documented"
    disposition: RE_VERIFY
tier3:
  - id: CP-1
    finding: "paperclip not a registered CIAgent project"
    disposition: REJECT_AS_CANDIDATE
    reason: "carry-forward from v1.2; closed by operator directive"
  - id: CP-2
    finding: "inboxos source has 0 paperclip references"
    disposition: RE_VERIFY
  - id: CP-3
    finding: "/root/workspace/paperclip/ unmodified by this scan"
    disposition: RE_VERIFY
final_candidates:
  count: 12
  accepted_count: 9
  deferred_count: 3
  rejected_count: 0
  ids: [REQ-INB-28, REQ-INB-29, REQ-INB-30, REQ-INB-31, REQ-INB-32, REQ-INB-33, REQ-INB-34, REQ-INB-35, REQ-INB-36, REQ-INB-37, REQ-INB-38, REQ-INB-39]
  accepted_ids: [REQ-INB-28, REQ-INB-29, REQ-INB-30, REQ-INB-31, REQ-INB-32, REQ-INB-33, REQ-INB-34, REQ-INB-36, REQ-INB-37]
  deferred_ids: [REQ-INB-35, REQ-INB-38, REQ-INB-39]
schema_impact: none
cross_project: 0
---/ci---
This commit is contained in:
2026-06-08 23:14:05 +00:00
parent 66ee9038da
commit 946b744a09
@@ -0,0 +1,646 @@
# InboxOS — v1.3 Ideation Candidates
> **Date:** 2026-06-08
> **Project:** InboxOS (`/INB/projects/inboxos`)
> **Milestone:** v1.3 (post-v1.2)
> **Source of ideation:** Tier 1 (mechanical / code-scraped) + Tier 2
> (backend-enriched, mining the v1.0/v1.1 post-hoc backlogs) + Tier 3
> (cross-project) — issued **from scratch** at the user's request,
> because the v1.3 research commit (`66ee903`) named INB-193 as the
> candidate source and the CTO has since closed that issue along
> with INB-183. The Gitea issue queue assigned to `cloudinit-bot` is
> now empty (verified: `tea issues list --assignee cloudinit-bot
> --owner jc-capital --repo inboxos --state open` returns **0 open
> issues**). The v1.3 candidate set is therefore built entirely
> from the existing codebase, the `post_hoc_review` backlogs, and
> the v1.3 research PIT items.
> **Ideator role:** `ci-ideation-agent`
> **Author status:** Ideation candidates only. **Not approved
> requirements.** All candidates are marked **[CANDIDATE]** until
> the CPO authors a matching entry in `docs/requirements.md`
> (CPO-owned, per board mandate `b49cfb7`).
---
## 1. CPO governance note
This ideation pass honors the board mandate recorded in commit
`b49cfb7` (`docs(seed): initialize requirements and roadmap
source-of-truth`):
- `docs/requirements.md` is CPO-owned. **Not modified.** Confirmed
byte-identical to the v1.1 / v1.2 close (only the 2026-06-08
CEO seed change-log row).
- `docs/roadmap.md` is CPO-owned. **Not modified.** Confirmed
byte-identical to the v1.1 / v1.2 close.
- The 14 v1.0 requirements (`REQ-INB-1` through `REQ-INB-14`) are
**[SHIPPED]** per `.ciagent/inboxos/CI-LOG.md`.
- The 11 v1.1 candidates (`REQ-INB-15` through `REQ-INB-25`) are
**[EXECUTED]** per the v1.1 acceptance gate at
`docs/operations-runbook.md §9.4` and tagged `v1.1.0`.
- The 1 v1.2 candidate (`REQ-INB-26`) is **[REJECTED — out of
domain]** per `.ciagent/inboxos/CI-LOG.md` (v1.2 close block) and
the disposition recorded in
`.ciagent/inboxos/ideation/v1.2-candidates.md §8`.
- `.ciagent/config.json` is **untouched** in the ideation phase;
the milestone row still says `v1.2 / status: complete`. The
v1.3 milestone does not register a new `phase:` row in the
config until the close commits the ship.
Edits made in this pass are confined to:
- `.ciagent/inboxos/ideation/v1.3-candidates.md` (this file — new)
- `.ciagent/inboxos/REQUIREMENTS.md` (append a "v1.3 candidate
requirements" block, no change to existing 14 + 11 + 1 rejected)
- `.ciagent/inboxos/ROADMAP.md` (append a "v1.3 ideation (Phase
01)" block, no change to Phase 6/7/8 prose or the existing v1.1
/ v1.2 ideation blocks)
The CPO is the only role that can promote any **[CANDIDATE]** in
this report to a real requirement by authoring the corresponding
entry in `docs/requirements.md`. The lead-developer is the
integrator for the follow-on PLAN phase and is the only role that
may add technical acceptance criteria to a candidate.
---
## 2. Source query
The `ciagent run --ideate` invocation specified: *"do full Tier 1
(mechanical / code-scraped) + Tier 2 (backend-enriched) + Tier 3
(cross-project) ideation from the codebase alone."* The user's
context note records that the Gitea issue queue assigned to
`cloudinit-bot` is now empty (0 open issues; CTO closed both
`INB-183` and `INB-193`). The tea invocation that confirms this
state is:
```
tea issues list --assignee cloudinit-bot --owner jc-capital \
--repo inboxos --state open
```
Result: **0 open issues**.
The full state of all inboxos issues (any assignee, any state)
shows that both issues the bot previously owned — `INB-183`
(opencode-local adapter PATH append, open since v1.1-Beta,
rejected in v1.2 as out-of-domain) and `INB-193` (the
`scripts/with-gitea-env.sh` wrapper per the v1.3 research commit
body) — have been **closed by the CTO** before this ideation pass.
The source of ideation is therefore the codebase itself, the
v1.0/v1.1/v1.2 post-hoc backlogs, the v1.3 research PIT items
(PIT-V1.3-1..3 from commit `66ee903`), and the v1.1 closure
backlog (`remaining_for_v1_2: [P1-1, P1-2, P2-1, P2-2]`
forwarded from v1.2 to v1.3 per `.ciagent/inboxos/CI-LOG.md`
v1.2 close block).
---
## 3. Tier 1 — Mechanical findings (code-scraped)
Tier 1 findings were produced by scanning `pipelines/`,
`.gitea/workflows/`, `docker/`, `scripts/`, `docs/`,
`.opencode/commands/`, `opencode.json`, `.env.example`, and
`scripts/*.sh` for `TODO`/`FIXME`/`XXX`/`HACK` markers, commented-
out code blocks, hardcoded paths / secrets / IPs, feature-flag
stubs, and documentation drift relative to the source.
The first four categories produced **zero hits**: no
`TODO`/`FIXME`/`XXX`/`HACK` markers in code, no commented-out
code blocks in `.py` or `.sh` files, no real secrets in
committed files, no IPs that would leak. The shell scripts are
all chmod 755 with `set -euo pipefail`. The drift items below
all map to either a known P1/P2 backlog entry or a real v1.3
opportunity that the mechanical scan surfaced.
| # | Finding (file:line) | Backlog ID | Candidate REQ | Parent REQ | Confidence | Effort | Schema |
|---|---------------------|------------|---------------|------------|------------|--------|--------|
| T1-1 | `docs/gitea-actions.md:95` hardcodes `cto-inboxos/inboxos` in a `curl` example (verify-runner step). The v1.1 review auto-applied the same fix to the runbook (`d530921`, runbook §5.1 + §10) and to the 3 new shell helpers (`7c20d5d`), but `docs/gitea-actions.md` was missed and still ships with the old owner string. P0 by the same reasoning as the v1.1 P0 sweep (operator would fail to verify the runners under the `jc-capital` migration if they copy-pasted this example). | n/a (v1.1 sweep was scoped to .md / .sh created or modified in v1.1; gitea-actions.md was last touched at Phase 4 / INB-33, before the org migration) | **REQ-INB-28** | REQ-INB-6, REQ-INB-10 | 0.90 | XS | no |
| T1-2 | `docs/operations-runbook.md:823` footer still says *"Next review: after the v1.1 ship (2026-06-08, milestone `milestone/v1.1-initial`)"*. v1.1 has shipped, v1.2 has shipped (tag v1.2.0 on `63c0f59`), and v1.3 is in the ideate phase on `milestone/v1.3-initial`. The footer pointer is stale by 2 milestones. P2 / cosmetic, but a v1.3 doc-hygiene item. | n/a (cosmetic, not in v1.1 backlog) | **REQ-INB-29** | REQ-INB-6 | 0.95 | XS | no |
| T1-3 | `docs/operations-runbook.md:285-289` §4.5 "Forward-pointer" says "Alerting is **out of scope** for v1.1; the runbook does not include alert rules (this is a v1.2 candidate per `.ciagent/inboxos/ideation/v1.1-candidates.md` Tier 2 T2-D). [...] The alert layer is the next v1.2 deliverable." v1.2 has shipped without delivering alerting (v1.2 was a 0/1 disposition; no alerting was in scope). The forward-pointer is now stale. | n/a (forward-pointer; not in v1.1 backlog) | **REQ-INB-30** | REQ-INB-6, REQ-INB-23 | 0.80 | XS | no |
| T1-4 | `docs/papra-write-policy.md:192` says *"covers 13 cases"* but `pipelines/_tests/test_papra_decide_offline.py` actually defines **15 test functions** (the two v1.1 additions — `test_papra_dry_run_override_wins` and `test_emit_papra_write_gate_event_logs_three_fields` — were never reflected in the doc count). Off-by-2, but visible to a new operator reading the doc and the test list side-by-side. | n/a (doc drift, not in v1.1 backlog) | **REQ-INB-31** | REQ-INB-9, REQ-INB-20 | 0.90 | XS | no |
| T1-5 | `docs/extraction-contract.md:40,98,102,161` cite four line ranges in `pipelines/common.py` that have drifted past the v1.0 + v1.1 line-shuffle. Verified: the v1.1 EXECUTE stage added 30+ lines to `LLMConfig.from_env` (now at line 536, doc cites `414-479`) and ~25 lines to `_ollama_call_one_model` (now at line 636, doc cites `605-624`); the `opencode_run_command` was reshaped (now at line 440, doc cites `378-407` for the opencode backend). An operator who grep-lands on the doc's line numbers and reads from there will read the wrong function. P2 / doc drift. | n/a (doc drift, not in v1.1 backlog) | **REQ-INB-32** | REQ-INB-4, REQ-INB-14 | 0.85 | S | no |
| T1-6 | `.env.example` is missing entries for the workflow env vars that have no default (or that have a literal-string default baked into the workflow). Specifically: `OLLAMA_API_KEY` (referenced in all 3 workflows, default empty), `INBOXOS_LLM_BACKEND` (live+historical+ci-pr, default `'ollama'`), `PAPRA_DRY_RUN` (live+historical, default `'true'`), `PAPRA_BODY_WRITE_MODULES` (live+historical, default `'crm,finance,legal'`), `PAPRA_METADATA_ONLY_MODULES` (live+historical, default `'intel,promotions'`), `MBOX_BUCKET` (historical-only, default falls back to `SEAWEEDFS_S3_BUCKET`), and `OPENCODE_NPM_VERSION` (historical-only, default `'latest'`). The existing `.env.example` documents `IMAP_*`, `NOCODB_*`, `SEAWEEDFS_*`, `PAPRA_*` (the bare connection vars), `OLLAMA_BASE_URL`, `GITEA_*`, and `OPENCODE_BIN` / `OPENCODE_PROMPT_DIR` — but the LLM-backend + Papra-tunables + MBOX_BUCKET + OPENCODE_NPM_VERSION knobs are not in the file at all. A new operator following the runbook will miss these. P2 / doc drift. | n/a (env-file drift, not in v1.1 backlog) | **REQ-INB-33** | REQ-INB-6, REQ-INB-9, REQ-INB-11 | 0.80 | S | no |
| T1-7 | `.gitea/workflows/ci-pr.yml` `fast-tests` job runs only 3 offline tests: `test_gitea_request_offline.py`, `test_mbox_stream.py`, `test_live_pipeline_offline.py` (lines 91-99). The v1.1 EXECUTE stage added **6 more pure-offline tests** (`test_papra_decide_offline.py`, `test_papra_index_offline.py`, `test_papra_link_parity_offline.py`, `test_metrics_offline.py`, `test_restore_offline.py`, `test_rotate_secrets_offline.py`) — all of which pass locally (v1.1 verify report records 30/30) — but **none of them are wired into the ci-pr merge gate**. The v1.1 verify report's "5 layers" claim about CI is satisfied, but a PR could regress `papra_index_upsert`, `papra_decide`, the metrics emitter, the secret-rotation helper, or the backup/restore contract without the merge gate noticing. P0 by the merge-gate-stays-clean standard. | n/a (post-v1.1 verify, surfaced in this scan) | **REQ-INB-34** | REQ-INB-8 | 0.90 | S | no |
| T1-8 | `opencode.json` is listed in `.gitignore` (line `opencode.json` in `.gitignore`) **and** is also tracked in git (verified: `git ls-files opencode.json` returns the path; `git log opencode.json` shows commits `350b902`, `ab7331d`, `051e565`, `c5b7cf8`, `1d74d85`). The file is a per-checkout override for the opencode CLI, but the gitignore pattern means a fresh `git status` will not show local modifications to it (because git ignores it). The result: an operator who edits `opencode.json` to switch model pin will see no diff and cannot revert through git. Cosmetic + ergonomics, but a real footgun for an INB-20 / model-pinning workflow. | n/a (post-v1.1 scan, surfaces a long-standing .gitignore oddity) | **REQ-INB-35** | REQ-INB-14, REQ-INB-11 | 0.65 | XS | no |
> **Tier 1 summary:** 8 findings. 2 P0 (T1-1, T1-7), 1 P2
> doc-counter (T1-4), 2 P2 doc-pointer (T1-2, T1-3), 3
> doc/ergonomics (T1-5, T1-6, T1-8). All in `.md` / `.yml` /
> `.env.example` / `.gitignore` — no `.py` TODOs, no
> commented-out code, no leaked secrets, no broken shell
> `set -euo pipefail` discipline (all 5 shell scripts are
> clean).
---
## 4. Tier 2 — Backend-enriched findings (judgment, code-reading)
Tier 2 candidates arise from mining the v1.0/v1.1/v1.2 post-hoc
backlogs (per `.ciagent/inboxos/CI-LOG.md` `post_hoc_review`
blocks) and the v1.3 research commit's PIT items
(PIT-V1.3-1..3 from `66ee903`). Each candidate references the
parent REQ-INB-* that it builds on and notes whether the change
would alter the NocoDB schema (per `docs/schemas.md`).
The v1.1 backlog (`remaining_for_v1_2: [P1-1, P1-2, P2-1, P2-2]`
per `CI-LOG.md:228`) is the primary source. Per the v1.2 close
block, those items remain in the v1.1 backlog file with no v1.2
additions; the v1.3 milestone is the next opportunity to clear
them. (Note: the v1.0 backlog items P1-3, P1-5, P2-1, P2-2
mentioned in the user's prompt were already closed in v1.1 via
REQ-INB-15..18; the v1.1 backlog uses the same P1/P2 labels for
*new* net items, not duplicates. The `CI-LOG.md:233` note
explicitly records this non-duplication.)
| # | Finding (source / file:line) | Backlog ID | Candidate REQ | Parent REQ | Confidence | Effort | Schema |
|---|-------------------------------|------------|---------------|------------|------------|--------|--------|
| T2-1 | `docs/operations-runbook.md` §6 ordering is `6.1 → 6.4 → 6.2 → 6.3` (verified at `docs/operations-runbook.md:476,508,558,565`). The v1.1 insertion of `§6.4 Secret rotation` (REQ-INB-21, commit `6067008`) between `§6.1` and `§6.2` left the section ordering non-monotonic. Cosmetic / nav, but the v1.1 review's P1-1 closure call is on the record (`CI-LOG.md:217-218`). | v1.1 P1-1 | **REQ-INB-36** | REQ-INB-6 | 0.95 | XS | no |
| T2-2 | `scripts/setup_gitea_secrets.sh:4,14,18,28` hardcode `cto-inboxos` (header comment x2, default `GITEA_OWNER="${GITEA_OWNER:-cto-inboxos}"`) 4 lines. The v1.1 review auto-applied the same fix to the 3 new shell helpers and the runbook (`7c20d5d`, `d530921`) but explicitly filed this script as "pre-existing — not in v1.1 diff" and tagged it for a v1.2 follow-up (`CI-LOG.md:219-220`); v1.2 was a 0/1 disposition so the carry-forward is now v1.3. The v1.0 `chore(config+secrets)` commit `a068c8a` updated `.ciagent/config.json` but missed this script. P1 by the same operator-action risk profile as the v1.1 P0 sweep. | v1.1 P1-2 | **REQ-INB-37** | REQ-INB-10 | 0.90 | XS | no |
| T2-3 | `scripts/apply_schemas.py --check` exercises the `papra_index` audit table (verified at `apply_schemas.py:443-466`: the `for audit in AUDIT_TABLES` loop calls `find_table` + `find_column` + `unique-constraint check`), but there is no offline test in `pipelines/_tests/` that drives `apply_schemas.py --check` to assert the papra_index path. The v1.0 §9.2 row 9 "apply_schemas.py --check exits 0" precedent is therefore not mirrored for the v1.1 papra_index table. `test_papra_index_offline.py` covers the runtime helper (`common.papra_index_upsert`, 3/3 pass) but not the schema-bootstrap path. The v1.1 backlog called this "Trivial addition (3-5 lines)"; the carry-forward is a v1.3 P2 item. | v1.1 P2-1 | **REQ-INB-38** | REQ-INB-5, REQ-INB-19 | 0.85 | XS | no |
| T2-4 | `pipelines/_tests/test_papra_link_parity_offline.py` is the v1.1 deferred-runtime test (1 test). It `import live_pipeline` (line 108), which in turn `from imapclient import IMAPClient` (`pipelines/live_pipeline.py:49`). The test counts as 1/1 in v1.1 must-have #11 evidence, but the runtime import chain is **not exercised in CI** (`ci-pr.yml` fast-tests does not list it; `imapclient` is a runtime-only dep, not in any test fixture). The v1.0 precedent accepted this disposition for `test_upsert_synthetic.py`, but the v1.1 cycle inherited it without further mitigation. P3 / accepted-precedent — but a v1.3 candidate could add a stub `imapclient` module (a 5-line shim in `pipelines/_tests/conftest.py` or a `sys.modules` injection in the test) so the chain imports cleanly in CI. Optional, low-priority. | v1.1 P2-2 | **REQ-INB-39** | REQ-INB-25, REQ-INB-8 | 0.55 | S | no |
| T2-5 | v1.3 research PIT-V1.3-1 (medium): the v1.3 candidate INB-193 (`scripts/with-gitea-env.sh` wrapper) was the planned v1.3 deliverable per the v1.3 research commit body. The CTO closed INB-193 before this ideation pass. The PIT is moot (no candidate to apply it to), but the **secret-scan pattern** it would have established (mktemp + chmod 600 + trap cleanup for runtime env-file fixtures) is reusable. v1.1 has no comparable pattern in `test_rotate_secrets_offline.py` (which instead bakes test values directly into `subprocess` `env=`). Low value as a standalone REQ; folded into a cross-cutting PIT-closure note in the v1.3 lessons (see §10). | v1.3 PIT-V1.3-1 (carried in spirit) | (no REQ; PIT-closure note only) | REQ-INB-9, REQ-INB-10 | n/a | n/a | n/a |
| T2-6 | v1.3 research PIT-V1.3-2 (low): same — moot because INB-193 is closed. The wrapper's INB-173 path-sovereignty rule (no mutation of `.ciagent/`) is a property the existing `setup_gitea_secrets.sh` and `rotate_secrets.sh` already honor (no `.ciagent/` writes), so no new requirement is needed. Cross-cutting observation only. | v1.3 PIT-V1.3-2 (carried in spirit) | (no REQ; PIT-closure note only) | REQ-INB-10 | n/a | n/a | n/a |
| T2-7 | v1.3 research PIT-V1.3-3 (low): the candidate INB-193 was going to need a `lint-shell` job in `ci-pr.yml` to wire the test into the merge gate. Moot because INB-193 is closed. **However**, the same need exists for the 6 v1.1 offline tests that T1-7 already flagged: a `lint-shell` (or `test-v11-offline`) job in `ci-pr.yml` would close T1-7 in one commit. PIT-V1.3-3 is therefore absorbed into REQ-INB-34. | v1.3 PIT-V1.3-3 (absorbed into T1-7) | (folded into REQ-INB-34) | REQ-INB-8 | 0.90 (absorbed) | (absorbed) | (absorbed) |
| T2-8 | `docs/schemas.md` and `scripts/apply_schemas.py` are **drift-free** at the column-list level (verified by python-side diff: `finance` (10 cols), `crm` (11), `intel` (9), `promotions` (11), `papra_index` (7) all match between doc and script). The v1.0 `9.2 row 9 'apply_schemas.py --check exits 0'` acceptance gate is documented; T2-3 above covers the offline-test gap. No new schema or doc drift. **Re-verify, not a finding.** | n/a (re-verify) | n/a | REQ-INB-5, REQ-INB-19 | n/a | n/a | n/a |
| T2-9 | All 5 `.opencode/commands/inboxos:*.md` prompts pin `model: ollama/gemma4:e4b` in the frontmatter (verified: classify + extract-crm + extract-finance + extract-intel + extract-promotions). The `pipelines/README.md`, `docs/extraction-contract.md`, `.env.example` line 96-99, and `opencode.json` all pin `gemma4:e4b` as the canonical production model. **No drift.** The v1.0 P-1 pitfall is closed; the v1.1 P1-5 (`.env.example` model comments) is closed. Re-verify, not a finding. | n/a (re-verify) | n/a | REQ-INB-11 | n/a | n/a | n/a |
| T2-10 | `pipelines/common.py:423-487` (`class OpenCodeConfig` + `def opencode_run_command`) is **kept for offline tests only** per the docstring at `common.py:455-461` ("This path is currently broken end-to-end; use `llm_run_command` with the `ollama` backend instead. This function is kept for offline tests and future opencode versions."). The `INBOXOS_LLM_BACKEND=opencode` path is wired into the workflow but defaults to `ollama` in all three workflows. **Not a candidate** — the dead code is intentional, documented, and exercised by the offline tests. Re-verify, not a finding. | n/a (re-verify) | n/a | REQ-INB-11, REQ-INB-14 | n/a | n/a | n/a |
> **Tier 2 summary:** 4 v1.3 candidates (T2-1..T2-4) plus 3 PIT
> closure notes (T2-5..T2-7) that fold into the existing Tier 1
> REQ-INB-34. The 3 v1.3 PIT items are absorbed as observations,
> not as new REQ-INB-* candidates, because INB-193 is closed and
> the wrapper is not being built. 3 re-verifications (T2-8..T2-10)
> confirm the v1.0/v1.1 drift closures are still in place.
---
## 5. Tier 3 — Cross-project findings
| # | Finding | Source | Candidate REQ | Confidence |
|---|---------|--------|---------------|------------|
| **CP-1** (carry-forward from v1.2 §5) | `paperclip` is **not a registered CIAgent project**. The only sibling projects are `coreci`, `ci`, `foo`, `inboxos` (per `.ciagent/config.json` `projects[]`). The v1.3 research PIT-V1.3-2 referenced the opencode-monorepo as a sovereignty boundary; with INB-193 closed, the carry-forward is unchanged. The operator's v1.2 directive ("NO DO NOT MAKE ADHOC CHANGES TO the paperclip monorepo") is the active posture. | `.ciagent/config.json` projects[]; `.ciagent/inboxos/CI-LOG.md:303` | (meta, no REQ) | n/a |
| **CP-2** (new) | The v1.3 inboxos docs / workflows do **not** reference `paperclip`, `opencode-monorepo`, or any other cross-project tree. Verified: `grep -rn "paperclip\|opencode-monorepo" docs/ pipelines/ scripts/ docker/ .gitea/ .env.example .opencode/ opencode.json` returns **0 hits**. The only paperclip references are in the `.ciagent/` governance files (REQUIREMENTS.md, ROADMAP.md, CI-LOG.md, v1.2-candidates.md), which is the correct scope: the rejection lineage is the only inboxos-side record, and the inboxos code itself is paperclip-blind. **No drift.** | inboxos source vs `.ciagent/` governance files | n/a (re-verify) | n/a |
| **CP-3** (new) | The `paperclip/` tree at `/root/workspace/paperclip/` is **not modified** by this ideation pass (the ideation pass makes no changes to inboxos source-tree files; the lead-developer's "do not touch paperclip" directive is honored). Verified by tree-comparison: no file under `paperclip/` has been edited, and the `git log --diff-filter=M -- paperclip/` on the inboxos repo returns empty (because paperclip is a separate repo entirely). | operator directive `CI-LOG.md:300`; this scan made zero source-tree changes | n/a (re-verify) | n/a |
> **Tier 3 summary:** 1 carry-forward meta-finding (CP-1,
> unchanged from v1.2) + 2 re-verifications (CP-2, CP-3). **No
> new cross-project candidates.** The inboxos bot's domain
> remains `pipelines/`, `docker/`, `.gitea/workflows/`, `docs/`,
> and `.opencode/commands/` only. The paperclip monorepo is
> out-of-scope by operator directive.
---
## 6. v1.3 ideation summary
| # | Candidate | Tier | Parent | Confidence | Effort | Cross-project |
|---|-----------|------|--------|------------|--------|---------------|
| 1 | **REQ-INB-28** — `docs/gitea-actions.md:95` `cto-inboxos` → `jc-capital` | T1-1 | REQ-INB-6, REQ-INB-10 | 0.90 | XS | no |
| 2 | **REQ-INB-29** — runbook footer "Next review" pointer (v1.1 → v1.3) | T1-2 | REQ-INB-6 | 0.95 | XS | no |
| 3 | **REQ-INB-30** — runbook §4.5 "Forward-pointer" (alerting → v1.2 deliverable, stale) | T1-3 | REQ-INB-6, REQ-INB-23 | 0.80 | XS | no |
| 4 | **REQ-INB-31** — `papra-write-policy.md:192` test count (13 → 15) | T1-4 | REQ-INB-9, REQ-INB-20 | 0.90 | XS | no |
| 5 | **REQ-INB-32** — `extraction-contract.md` 4 stale `pipelines/common.py:` line refs | T1-5 | REQ-INB-4, REQ-INB-14 | 0.85 | S | no |
| 6 | **REQ-INB-33** — `.env.example` missing 7 workflow env vars (OLLAMA_API_KEY, INBOXOS_LLM_BACKEND, PAPRA_DRY_RUN, PAPRA_BODY_WRITE_MODULES, PAPRA_METADATA_ONLY_MODULES, MBOX_BUCKET, OPENCODE_NPM_VERSION) | T1-6 | REQ-INB-6, REQ-INB-9, REQ-INB-11 | 0.80 | S | no |
| 7 | **REQ-INB-34** — Wire the 6 v1.1 offline tests (`test_papra_*`, `test_metrics_*`, `test_restore_*`, `test_rotate_secrets_*`) into `ci-pr.yml` merge gate | T1-7 + T2-7 (absorbed PIT-V1.3-3) | REQ-INB-8 | 0.90 | S | no |
| 8 | **REQ-INB-35** — `.gitignore` `opencode.json` line shadows a tracked file (footgun for INB-20 model-pin workflow) | T1-8 | REQ-INB-14, REQ-INB-11 | 0.65 | XS | no |
| 9 | **REQ-INB-36** — Runbook §6 ordering: renumber to `6.1 → 6.2 → 6.3 → 6.4` | T2-1 (v1.1 P1-1) | REQ-INB-6 | 0.95 | XS | no |
| 10 | **REQ-INB-37** — `scripts/setup_gitea_secrets.sh` `cto-inboxos` → `jc-capital` (4 lines) | T2-2 (v1.1 P1-2) | REQ-INB-10 | 0.90 | XS | no |
| 11 | **REQ-INB-38** — Add `apply_schemas.py --check` offline test for `papra_index` (3-5 lines) | T2-3 (v1.1 P2-1) | REQ-INB-5, REQ-INB-19 | 0.85 | XS | no |
| 12 | **REQ-INB-39** — `test_papra_link_parity_offline.py` runtime-deferred disposition: stub `imapclient` for CI | T2-4 (v1.1 P2-2) | REQ-INB-25, REQ-INB-8 | 0.55 | S | no |
| - | (meta) **CP-1** — `paperclip` is not a registered CIAgent project (carry-forward) | T3 (carry) | n/a | n/a | n/a | yes |
| - | (re-verify) **CP-2** — inboxos source has zero paperclip references | T3 (re-verify) | n/a | n/a | n/a | no |
| - | (re-verify) **CP-3** — `/root/workspace/paperclip/` not modified by this scan | T3 (re-verify) | n/a | n/a | n/a | yes |
**Total candidates:** 12 (REQ-INB-28 through REQ-INB-39)
**Tier 1 contribution:** 8/12 (REQ-INB-28..35)
**Tier 2 contribution:** 4/12 (REQ-INB-36..39; 3 PIT closure notes folded in)
**Tier 3 contribution:** 0 REQ (1 carry-forward meta + 2 re-verifications)
**Cross-project (paperclip):** 0 candidates (CP-1 closed by negation, CP-2 / CP-3 are re-verifications)
The v1.3 candidate set is **drift-heavy / code-light**: 9 of 12
candidates are doc or env-file hygiene (XS effort, no schema
impact), 2 are test-surface (S effort, no schema impact), and 1
is a `.gitignore` ergonomics fix (XS). **No NocoDB schema
impact** across the full set; v1.3 is a tools/wrappers milestone
in the v1.3 research's framing, and these candidates are the
mechanical fallout of 3 prior milestones shipping in succession.
---
## 7. Disposition detail for accepted candidates
The 12 candidates separate into three disposition groups. All 12
are **[CANDIDATE]** until the CPO authors matching entries in
`docs/requirements.md`; the lead-developer is the integrator for
the follow-on PLAN phase.
### 7.1 ACCEPT (recommended for v1.3 PLAN)
These 9 candidates are mechanical fixes with no design judgment
needed; the lead-developer can scope them into a single PLAN
wave (the v1.3 research suggested a single-issue milestone, but
the v1.3 candidate set is much larger than INB-193 alone because
the CTO closed INB-193 and the backlog is now sourced from
codebase drift alone).
- **REQ-INB-28** (P0, cto-inboxos drift in gitea-actions.md, same
risk profile as v1.1 P0 sweep): ACCEPT. **Required** for v1.3.
This is a 1-line doc fix. The lead-developer should land it in
the same commit as REQ-INB-37 (the corresponding
`setup_gitea_secrets.sh` fix) so the cto-inboxos → jc-capital
migration is closed in one PR.
- **REQ-INB-29** (P2, runbook footer "Next review" → v1.3 pointer):
ACCEPT. **Required** for v1.3 — the footer is two milestones
stale and a v1.3 ship without updating it leaves a v1.4 audit
trail with a misleading "next review" line.
- **REQ-INB-30** (P2, runbook §4.5 forward-pointer v1.2 → v1.3):
ACCEPT. **Required** for v1.3 — the v1.2 alerting deliverable
was never built, and the doc should reflect the v1.3 reality
(alerting is still not in scope; v1.3 is doc-hygiene, not
observability).
- **REQ-INB-31** (P2, papra-write-policy.md test count 13 → 15):
ACCEPT. **Required** for v1.3 — pure doc fix.
- **REQ-INB-32** (P2, extraction-contract.md 4 stale line refs):
ACCEPT. **Required** for v1.3 — a 4-line edit in
extraction-contract.md to re-cite `LLMConfig.from_env()` at
`pipelines/common.py:536`, `ollama_run_command` at
`pipelines/common.py:609`, `_ollama_call_one_model` at
`pipelines/common.py:636`, and the opencode backend at
`pipelines/common.py:440` (verified above).
- **REQ-INB-33** (P2, .env.example missing 7 workflow env vars):
ACCEPT. **Required** for v1.3 — a 7-entry addition to
`.env.example` (commented-out, with the same default the
workflow bakes in: `OLLAMA_API_KEY=""`,
`INBOXOS_LLM_BACKEND=ollama`, `PAPRA_DRY_RUN=true`,
`PAPRA_BODY_WRITE_MODULES=crm,finance,legal`,
`PAPRA_METADATA_ONLY_MODULES=intel,promotions`,
`MBOX_BUCKET=`, `OPENCODE_NPM_VERSION=latest`). This brings
the env-file into 1:1 alignment with the workflow defaults
the operator can grep.
- **REQ-INB-34** (P0, wire 6 v1.1 offline tests into ci-pr merge
gate): ACCEPT. **Required** for v1.3 — the highest-impact
candidate in the set. A 6-line `run: python
pipelines/_tests/test_X_offline.py` block (or one batched
heredoc that calls all 6 in sequence, matching the existing
`test_historical_pipeline_offline` fast-subset pattern at
`ci-pr.yml:106-134`). The lead-developer should also absorb
the v1.3 PIT-V1.3-3 ("wire the test into CI lint") into this
candidate.
- **REQ-INB-36** (P1, runbook §6 renumbering 6.1 → 6.2 → 6.3 →
6.4): ACCEPT. **Required** for v1.3 — moves §6.4 to its
proper position. Closes v1.1 backlog P1-1.
- **REQ-INB-37** (P1, setup_gitea_secrets.sh cto-inboxos →
jc-capital): ACCEPT. **Required** for v1.3 — 4-line edit.
Closes v1.1 backlog P1-2. Pair with REQ-INB-28 for a
single-PR cto-inboxos → jc-capital migration closure.
### 7.2 DEFER (low value or low confidence)
These 3 candidates are real findings but with marginal value
or low confidence; defer to a future milestone.
- **REQ-INB-35** (T1-8, .gitignore opencode.json line shadows a
tracked file): DEFER. The `opencode.json` file is committed
in the git history (5 commits) and the .gitignore pattern is
intentional defense-in-depth (a per-checkout override). The
footgun is real but minor: an operator who edits
`opencode.json` to switch model pin can `git diff
opencode.json` directly (the file is still tracked), they
just won't see it in `git status` of an unrelated change.
**Confidence 0.65** is the lowest in the set, and the fix
(removing the .gitignore line) opens a separate question
about whether the file should be tracked at all. Defer to
v1.4+ as a §10 lessons item.
- **REQ-INB-38** (T2-3, apply_schemas.py --check offline test
for papra_index): DEFER. The mechanical fix is 3-5 lines, but
the test would have to mock the NocoDB HTTP layer (similar to
the pattern in `test_papra_index_offline.py:144`'s
`FakeNoco`). The v1.1 backlog called it "Trivial addition
(3-5 lines)"; in practice the offline-test host has no
NocoDB to check, so the test would be a unit-level stub that
asserts the script's column-list parsing, not a true
`--check` integration. **Confidence 0.85** but **value 0.40**
(the runtime path is already covered by
`test_papra_index_offline.py`). Defer to v1.4+ unless the
v1.3 PLAN bundles it with REQ-INB-34 for one-off test wiring.
- **REQ-INB-39** (T2-4, test_papra_link_parity imapclient
runtime-stub): DEFER. The v1.0 and v1.1 cycles both accepted
the deferred-runtime disposition (v1.0 for
`test_upsert_synthetic.py`, v1.1 for
`test_papra_link_parity_offline.py`). The precedent is
documented; the v1.1 P2-2 backlog called it "Same
accepted-precedent disposition as v1.0's
test_upsert_synthetic.py imapclient path." The 5-line
`sys.modules["imapclient"] = types.ModuleType(...)` shim is
a small fix but **confidence 0.55** — the shim has to
satisfy the `from imapclient import IMAPClient` chain in
`live_pipeline.py:49` without breaking the existing
`live_pipeline` semantics, and the offline test host
installs `imapclient` already (per the v1.1
`pip install` step at `ci-pr.yml:80-87`). Defer to v1.4+
unless the lead-developer is willing to take a swing at
the shim.
### 7.3 REJECT (not candidates)
- **CP-1 (carry-forward paperclip meta)**: REJECT. The
operator's v1.2 directive closed this by negation
(`CI-LOG.md:303`). No change. The CP-1 finding is a
precondition question for cross-project handoffs, and no
v1.3 candidate requires a handoff (INB-193 is closed).
- **CP-2 (re-verify no paperclip refs)**: REJECT. Re-verification
only. No candidate needed.
- **CP-3 (re-verify paperclip tree not modified)**: REJECT.
Re-verification only. The ideation pass made zero changes
to `/root/workspace/paperclip/`.
- **T2-5, T2-6, T2-7 (v1.3 PIT items)**: REJECT as standalone
REQs. The candidate INB-193 is closed; the PIT items describe
failure modes for a candidate that no longer exists. T2-7
(PIT-V1.3-3 "wire the test into CI lint") is **absorbed into
REQ-INB-34** because the same need exists for the 6 v1.1
offline tests. T2-5 (PIT-V1.3-1 secret-scan pattern) and
T2-6 (PIT-V1.3-2 path sovereignty) are recorded in §10
lessons as reusable patterns for future candidates, not as
requirements.
- **T2-8 (schemas.md vs apply_schemas.py drift re-verify)**:
REJECT. Re-verification only. Drift-free at the column-list
level.
- **T2-9 (model pin re-verify)**: REJECT. Re-verification only.
All 5 prompts + .env.example + opencode.json pin
`gemma4:e4b`.
- **T2-10 (opencode backend dead code re-verify)**: REJECT.
Re-verification only. The dead code is intentional, documented,
and exercised by the offline tests.
---
## 8. Final candidates for PLAN/EXECUTE
| # | Candidate | Disposition | Effort | Notes |
|---|-----------|-------------|--------|-------|
| 1 | REQ-INB-28 | ACCEPT | XS | 1-line doc fix; pair with REQ-INB-37 |
| 2 | REQ-INB-29 | ACCEPT | XS | 1-line footer fix |
| 3 | REQ-INB-30 | ACCEPT | XS | 4-line forward-pointer fix |
| 4 | REQ-INB-31 | ACCEPT | XS | 1-line test-count fix |
| 5 | REQ-INB-32 | ACCEPT | S | 4-line line-ref fix in extraction-contract.md |
| 6 | REQ-INB-33 | ACCEPT | S | 7-entry .env.example addition |
| 7 | REQ-INB-34 | ACCEPT | S | 6-line ci-pr.yml test wiring; absorbs PIT-V1.3-3 |
| 8 | REQ-INB-35 | DEFER | XS | .gitignore opencode.json line — defer to v1.4 |
| 9 | REQ-INB-36 | ACCEPT | XS | 4-line runbook §6 renumber; closes v1.1 P1-1 |
| 10 | REQ-INB-37 | ACCEPT | XS | 4-line setup_gitea_secrets.sh; closes v1.1 P1-2; pair with REQ-INB-28 |
| 11 | REQ-INB-38 | DEFER | XS | apply_schemas.py --check offline test — defer to v1.4 |
| 12 | REQ-INB-39 | DEFER | S | test_papra_link_parity imapclient shim — defer to v1.4 |
**9 ACCEPT candidates** (REQ-INB-28, 29, 30, 31, 32, 33, 34, 36, 37).
**3 DEFER candidates** (REQ-INB-35, 38, 39).
**0 REJECT candidates.**
**Accept ratio:** 9/12 (75%) — high, but the value is concentrated
in the 2 P0 items (REQ-INB-28, REQ-INB-34) and the 7 doc/env
hygiene items (REQ-INB-29, 30, 31, 32, 33, 36, 37). The
DEFER-set is all low-confidence or low-value.
**Cross-project:** 0 candidates (CP-1 closed by negation; CP-2 /
CP-3 re-verifications only).
**Schema impact:** 0 across all 12 candidates. v1.3 is a
doc-hygiene + test-wiring + env-file-drift milestone. **No
NocoDB schema changes.** This is consistent with the v1.3
research commit body: "v1.3 is a tools/wrappers milestone; the
pipeline is not touched" and "No new services, no schema
changes, no LLM model changes" — except the v1.3 research was
written for INB-193 (the wrapper) and that issue is now closed,
so v1.3 has narrowed to the codebase-drift fallout that this
scan surfaced.
**Suggested PLAN shape:** 3 waves. Wave 1 = the 2 P0 items
(REQ-INB-28 + REQ-INB-37, then REQ-INB-34) — closes the
cto-inboxos drift in 2 files and the CI test gap in 1 file.
Wave 2 = the 7 doc/env hygiene items (REQ-INB-29, 30, 31, 32,
33, 36) — 6 small doc edits + 1 .env.example addition. Wave 3
= nothing (no execute items remaining). The lead-developer
should confirm this shape before the PLAN commit; the
candidates are mechanical enough that the waves can collapse
into 2 if the lead-developer prefers.
**Tag:** v1.3.0. Ship pattern identical to v1.1 (Papra Gate + DR
+ Observability) and v1.2 (0/1 disposition): FF-merge
`phase/01-v1.3-execute` → `milestone/v1.3-initial` → `main`,
push tag, push milestone branch, create Gitea release.
---
## 9. Post-hoc review items
**v1.3 backlog (filed for v1.4+ follow-up):**
- **REQ-INB-35** — `.gitignore opencode.json` line shadows a
tracked file. Defer to v1.4 unless the lead-developer
decides to take a swing.
- **REQ-INB-38** — `apply_schemas.py --check` offline test for
`papra_index` table. Defer to v1.4; the value is marginal
because the runtime path is already covered by
`test_papra_index_offline.py`.
- **REQ-INB-39** — `test_papra_link_parity_offline.py`
imapclient runtime-shim. Defer to v1.4; the
accepted-precedent disposition is on the v1.0 and v1.1
audit trail.
**v1.1 backlog still open** (none — all 4 closed in v1.3):
- v1.1 P1-1 (runbook §6 ordering) → **closed by REQ-INB-36**
- v1.1 P1-2 (setup_gitea_secrets.sh owner) → **closed by REQ-INB-37**
- v1.1 P2-1 (apply_schemas.py papra_index --check test) →
**deferred to v1.4+ via REQ-INB-38**
- v1.1 P2-2 (papra_link_parity runtime-only) → **deferred to
v1.4+ via REQ-INB-39**
**v1.0 backlog still open** (none — all closed in v1.1):
P1-3, P1-5, P2-1, P2-2 all closed via REQ-INB-15, 16, 17, 18.
Verified at `CI-LOG.md:233` and the v1.1 commit log
(`6b05e8d`, `87adaed`, `7fb1dd4`, `42cd1b0`).
**v1.3 PIT items (re-absorbed):**
- PIT-V1.3-1 (medium, secret-scan pattern) → §10 lessons
- PIT-V1.3-2 (low, .ciagent/ sovereignty) → §10 lessons
- PIT-V1.3-3 (low, CI lint wiring) → absorbed into REQ-INB-34
**Cross-project carries:**
- CP-1 (paperclip not a registered CIAgent project) →
unchanged from v1.2, closed by operator directive.
---
## 10. Lessons
- **L-IDEATE-V1.3-01**: When the Gitea issue queue is empty
and the CTO has closed the issues named in the v1.3 research
commit (INB-183 + INB-193), the IDEATE pass must explicitly
pivot to **codebase-drift ideation** rather than issue-driven
ideation. The v1.3 research commit's "single-issue v1.3
milestone" framing (ED-V1.3-2) is now stale; the milestone
has to be re-scoped to the mechanical drift this scan
surfaced. The lead-developer should confirm the re-scope
before PLAN.
- **L-IDEATE-V1.3-02**: The drift-density of the inboxos
codebase increased monotonically across v1.0 → v1.1 → v1.2
(zero P1/P2 at v1.0 close, 6 P1 + 3 P2 at v1.0 review, 2 P1
+ 2 P2 at v1.1 close, 0 source-tree changes at v1.2 close,
and now 12 candidates at the v1.3 IDEATE). The pattern is
consistent: each milestone ship leaves drift in the docs /
env-files / workflow comments that the next IDEATE pass
surfaces. A standing "post-ship doc-hygiene pass" in the
COMPLETE phase of every milestone would catch this without
waiting for the next IDEATE. **The v1.3 PLAN should consider
adding this as a CI-LOG post-hoc-review step** (not a REQ).
- **L-IDEATE-V1.3-03**: 9 of 12 v1.3 candidates are XS or S
effort doc/env-hygiene fixes. The lead-developer could land
them as a single `chore(docs): v1.3 doc-hygiene sweep` PR
(5-7 files, ≤ 50 line changes) rather than 9 separate
micro-PRs. The trade-off: a single sweep PR has a higher
audit-trail value but a higher per-PR review cost; the
per-REQ approach matches the v1.1 / v1.2 1-REQ-per-PR
pattern. The lead-developer's call.
- **L-IDEATE-V1.3-04**: The `papra-write-policy.md:192` "13
cases" claim and the runbook footer "Next review: after the
v1.1 ship" stale pointer are **both** artifacts of the same
v1.1 ship pattern: the v1.1 EXECUTE stage added tests +
acceptance-gate content but did not update the prose
counters / footers in the existing docs. A simple
pre-merge-grep for `1[0-9] cases` and `Next review` would
have caught both. **Future IDEATE passes should add this
grep to the mechanical scan** (Tier 1).
- **L-IDEATE-V1.3-05**: The `opencode.json` file is in
`.gitignore` **and** tracked by git. The pattern is
intentional defense-in-depth (allows local override while
still keeping a committed default), but the footgun is
real: a `git status` of an unrelated change will not show
an `opencode.json` edit, and a new operator won't know the
file is tracked unless they `git log opencode.json`. The
fix is to either (a) remove the file from .gitignore
(declares "this file is the canonical, do not override"),
or (b) keep the .gitignore line and add a comment to
`opencode.json` ("tracked; .gitignore is for local override")
so the operator knows. REQ-INB-35 is deferred; this is a
judgment call for the lead-developer.
- **L-IDEATE-V1.3-06 (PIT-V1.3-1 / V1.3-2 carry-forward)**:
The v1.3 research's PIT-V1.3-1 (mktemp + chmod 600 + trap
secret-file pattern) and PIT-V1.3-2 (.ciagent/ sovereignty)
are reusable patterns even though INB-193 is closed. If a
future candidate requires a runtime env-file fixture
(similar to the `with-gitea-env.sh` wrapper), the test
harness should follow the mktemp + chmod 600 + trap pattern
and assert no `.ciagent/` mutation. This is a **template
recommendation**, not a requirement.
- **L-IDEATE-V1.3-07 (carries v1.2 L-IDEATE-01)**:
Single-issue directed ideation where the only assigned
issue is cross-project is a trap; the disposition layer
needs an explicit "out-of-domain" path separate from the
standard accept/skip/modify loop. v1.2 honored this
(REQ-INB-26 rejected). v1.3 honors it differently: the
planned v1.3 candidate INB-193 was closed by the CTO
before IDEATE, so the v1.3 milestone has no assigned
issue at all and the IDEATE pass is codebase-drift-driven.
---
## 11. Tier 1 / 2 / 3 cross-reference
| Tier | Findings | REQ-INB-* | Re-verifications | Meta / rejected |
|------|----------|-----------|------------------|-----------------|
| **Tier 1** (mechanical / code-scraped) | 8 (T1-1..T1-8) | 8 (REQ-INB-28..35) | 0 | 0 |
| **Tier 2** (backend-enriched / backlog mining) | 7 (T2-1..T2-7) | 4 (REQ-INB-36..39) | 3 (T2-8..T2-10) | 3 PIT items absorbed or lessons-only |
| **Tier 3** (cross-project) | 1 carry (CP-1) | 0 | 2 (CP-2, CP-3) | 1 carry-forward closed by negation |
| **Total** | 16 raw findings | 12 candidates | 5 re-verifications | 4 meta / PIT-closure |
**Backlog coverage** (v1.1 backlog items in v1.3 candidates):
- v1.1 P1-1 (§6 ordering) → **REQ-INB-36** (ACCEPT, XS)
- v1.1 P1-2 (setup_gitea_secrets.sh owner) → **REQ-INB-37**
(ACCEPT, XS)
- v1.1 P2-1 (apply_schemas.py --check papra_index) →
**REQ-INB-38** (DEFER, XS)
- v1.1 P2-2 (papra_link_parity imapclient shim) →
**REQ-INB-39** (DEFER, S)
**v1.3 research PIT items in v1.3 candidates:**
- PIT-V1.3-1 → §10 lessons (L-IDEATE-V1.3-06)
- PIT-V1.3-2 → §10 lessons (L-IDEATE-V1.3-06)
- PIT-V1.3-3 → absorbed into **REQ-INB-34** (ACCEPT, S)
**New v1.3 candidates (not in any prior backlog):**
- REQ-INB-28 (T1-1, cto-inboxos in gitea-actions.md, missed by
v1.1 sweep) — same risk class as v1.1 P0 but missed
- REQ-INB-29 (T1-2, runbook footer stale by 2 milestones)
- REQ-INB-30 (T1-3, runbook §4.5 forward-pointer stale)
- REQ-INB-31 (T1-4, papra-write-policy.md test count off-by-2)
- REQ-INB-32 (T1-5, 4 stale line refs in extraction-contract.md)
- REQ-INB-33 (T1-6, 7 missing .env.example entries)
- REQ-INB-34 (T1-7, 6 v1.1 offline tests not in ci-pr merge gate)
- REQ-INB-35 (T1-8, .gitignore shadows tracked opencode.json)
**v1.0 leftover items (per user's prompt) — all already closed
in v1.1:**
- v1.0 P1-3 (inb-28-report empty row counts) → **closed**
REQ-INB-18, commit `42cd1b0`
- v1.0 P1-5 (`.env.example` model comments) → **closed**
REQ-INB-15, commit `6b05e8d`
- v1.0 P2-1 (runbook §9.1 #12 glob) → **closed** REQ-INB-16,
commit `87adaed`
- v1.0 P2-2 (runbook §6.1 secret count) → **closed**
REQ-INB-17, commit `7fb1dd4`
**v1.0 P1-1, P1-2, P1-4, P1-6, P2-4** (also from the v1.0
backlog, not in the user's prompt) — all closed in v1.0 fix
commit `32c076c` (P1-2, P1-4, P1-6) or v1.1 commits
`df88e8b` (P1-1, P2-4). The `CI-LOG.md:233` note explicitly
records the v1.0 backlog was emptied by v1.1.
**Acceptance posture:** The 9 ACCEPT candidates clear the
v1.1 backlog (P1-1, P1-2) and close 7 newly-surfaced doc-hygiene
items. The 3 DEFER candidates are filed for v1.4+ in
§9. The 0 REJECT candidates mean the v1.3 milestone ships
with a 9/12 disposition (or higher if the lead-developer
bundles one or more DEFER items into the v1.3 PLAN).
**Honest confidence statement:** Tier 1 confidence is
0.65-0.95; Tier 2 confidence is 0.55-0.95; Tier 3
re-verifications are n/a. The lowest-confidence finding is
**REQ-INB-39** (0.55) — the imapclient runtime-shim has
non-trivial test-surface implications that the v1.0 / v1.1
precedent chose to accept rather than fix. The highest-
confidence finding is **REQ-INB-29** (0.95) — the runbook
footer is unambiguously two milestones stale. The IDEATE
output is intentionally not padded: 12 candidates, all
backed by file:line evidence, all dispositioned. The 3
re-verifications (T2-8, T2-9, T2-10, CP-2, CP-3) confirm the
v1.0 / v1.1 drift closures are still in place; they are
not candidates but are recorded to preserve the audit trail.