SESSION_2026-09-01_p4_credentials_and_preflight_checks.md #1

  • //
  • j2j/
  • dev/
  • ai_dev_support/
  • SESSION_2026-09-01_p4_credentials_and_preflight_checks.md
  • Markdown
  • View
  • Commits
  • Open Download .zip Download (10 KB)

Session Log: P4 Credential Redesign, New Preflight Checks, Live-Readiness Check

Date: 2026-09-01 (continuation of the 2026-08-31 dry-run session) Author: Claude (Claude Code session) Requested by: Tom Tyler


Context

Continuation of sync_jira_to_p4jobs.sh hardening, picking up after SESSION_2026-08-31_first_dry_run.md (which found and fixed the stdout-contamination silent-data-loss bug, change 33384). Tonight's work, in order:

  1. Aligned further with the SDP Bash Coding Standard and its template.sh (change 33383): colorized status output (msg_green/msg_yellow/ msg_red), a LOGGING: section in -man documenting the self-logging behavior, -D for full set -x tracing, get_old_log_timestamp() inlined from the logging.lib equivalent, and moving the EXIT/SIGINT/ SIGTERM trap to the very first line of Main Program so config/lock failures also complete through terminate() (previously they bypassed it and skipped the final summary line). Also fixed a pre-existing ShellCheck warning (dead pattern alternative in the status-mapping case) while at it.
  2. Scaled back the stdout/stderr fix per feedback. The original fix for the stdout-contamination bug moved msg()/dbg()/detail() themselves to stderr -- correct, but "a bit extreme" for a two-call-site problem, and risked complicating future color-output handling for every caller. Reverted those shared functions to plain stdout and instead redirect only the ~4 specific detail()/warnmsg() calls inside jira_get() and map_jira_project_to_p4() (the two functions actually captured via command substitution) directly to stderr (change 33388). Saved as a general lesson in memory: prefer narrow, call-site-specific fixes over changing widely-shared helpers.
  3. Fixed a misleading Limited: no (-max 5) summary line -- showing the configured cap when it wasn't actually the limiting factor implied it applied when it didn't (change 33389).
  4. Established a version-bump policy, per Tom's request: bump the script's declare Version="X.Y.Z" (semver) with every submit that touches it -- Major/Minor/Patch per the usual rules. Caught up from the untracked original 1.0.0 to 2.0.0 to reflect the accumulated breaking changes already made this week (change 33386), then continued bumping with each subsequent submit. Saved as a standing memory so this isn't forgotten in future sessions.
  5. Replaced the P4 ticket-handling mechanism entirely. Previously the script read a P4PasswdFile into a variable and passed it via P4PASSWD. Tom asked to stop passing a ticket at all and instead reference a P4CONFIG-format file. This went through two attempts:
    • First attempt (wrong): tried p4 -config <path>. That flag does not exist in this p4 client (verified directly against p4 -h and p4 help environment -- P4CONFIG is only ever a filename p4 discovers via directory-walk, not an absolute-path flag). Caught this myself before the first submit and switched to parsing P4PORT/P4USER/P4TICKETS/P4TRUST out of the file and exporting them per-call via env (this working version is what actually shipped as change 33390 / v3.0.0) -- but several -man/README example commands for one-time human setup still showed the hallucinated p4 -config ... trust -y / login, which Tom caught the next message ("Yikes, I see a hallucination in there").
    • Second attempt (correct, change 33391 / v3.1.0): per Tom's specific direction, load_p4_config() now just exports P4CONFIG="$P4ConfigFile" (an absolute P4CONFIG is used directly, no directory-walk, and its values take precedence over the ambient environment) and P4ENVIRO=/dev/null/.p4enviro (so no personal ~/.p4enviro leaks in). p4 itself then reads P4PORT/P4USER/P4TICKETS/P4TRUST from the file and resolves the ticket from P4TICKETS entirely on its own -- verified every piece (absolute-path P4CONFIG behavior, P4ENVIRO override, the TicketExpiration ztag field and its not-logged-in empty-string case) against the real p4 client before writing any code, this time.
    • Per further feedback, the script doesn't track P4PORT/P4USER itself at all anymore -- every p4 call picks them up from P4CONFIG directly -- and load_p4_config() doesn't validate the file's contents beyond confirming it exists; any misconfiguration surfaces naturally from the preflight checks that follow, rather than this script re-implementing p4's own validation.
    • Also fixed the example P4PORT from ssl:workshop.perforce.com:1666 to public.perforce.com:1666 -- the Public Depot isn't actually SSL-encrypted (it's a public, read-visible server) -- and changed StateDir's default from ${P4HOME:-/p4/1}/tmp/jira_sync to ${P4TMP:-/tmp}/jira_sync (same value on a standard SDP instance-1 host, cleaner fallback off SDP).
  6. Added two new preflight checks, both bailing with a clear message before any syncing starts rather than letting every job upsert fail individually:
    • check_p4_login() (change 33391): verifies the configured P4USER has a ticket with at least 60 minutes remaining, via p4 -ztag -F '%TicketExpiration%' login -s. An empty result means not logged in at all.
    • check_p4_access() (change 33393): verifies p4 protects -m reports admin or super -- confirmed directly via p4 help job that -f (which this script always uses, to set ReportedDate/ModifiedBy/ModifiedDate) requires admin.

Live-readiness check

Tom set up a dedicated service account, bot_p4jira, with its own P4TICKETS file, and asked directly: have we pushed anything live yet, and do we think it'll work? Answer: no live runs yet, everything has been -C ... -max N -v N with no -y. Checked three things live against the Public Depot (all read-only, zero risk) to answer honestly rather than guess:

  • p4 jobspec -o: real field names/values match exactly what the script writes (Status/Type enums, perforce-software-sdp present in the Project enum).
  • p4 job -o SDP-1172: came back as a blank template, confirming most/all of a first live run would be creating jobs, not updating existing ones -- consistent with the tool's whole premise (Public Depot jobs stopped tracking JIRA a while back).
  • p4 protects -m: initially reported write, not admin -- which would have made every live job upsert fail on the -f flag. Tom granted admin access mid-session; re-checked and confirmed admin. This is exactly the gap check_p4_access() (above) now catches automatically.

Net: as of this session, the identified live-readiness blocker (insufficient P4 access) has been resolved and both new preflight checks pass. No live run has been attempted; Tom deferred that to a future session.

Design note for later: -batch as a separate option from -max

Tom observed that -max currently always blocks watermark advancement (true, by design -- it exists as a pilot/safety-valve cap: touch a few real issues, and if anything's wrong, rerun the exact same ones after fixing config rather than skipping past unreviewed data). He raised a second, different use case: processing a large backlog in controlled batches (e.g. 50 at a time) where the watermark should advance after each clean batch, making forward progress across repeated invocations. Proposed handling this as a new -batch option, mutually exclusive with -max, rather than changing -max's existing behavior. Captured here, not implemented yet.

Three things worth working out before building it:

  1. Needs to be a distinct, explicit flag (not a mode of -max) so the existing pilot-cap safety property doesn't quietly change for anyone already using -max that way.
  2. The watermark-advance target differs from a normal full run. A full clean run advances to RunStartTime (everything up to "now" has been verified). A batch-capped run has only verified issues up to the updated timestamp of the last issue actually processed (in the ORDER BY updated ASC stream) -- advancing to "now" would skip unverified issues. -batch mode would need to track and persist that last-processed timestamp instead of reusing the existing RunStartTime-based logic.
  3. Multi-project runs make this a real correctness risk, not just an edge case. The watermark is one shared value across every configured JiraProjects entry. If a batch cap cuts the run short partway through project B, with project C not yet even queried this run, advancing the shared watermark to B's cutoff point would silently skip project C's entire unprocessed backlog between the old watermark and that cutoff -- C's own progress was never actually verified this run. Safest options: (a) only support -batch when a single project is targeted via -p (much smaller, safer first step), or (b) move to a per-project watermark store (bigger change -- the watermark file becomes keyed per project). Lean toward (a) if/when this gets built.

Outstanding items (not done this session)

  1. -batch option (above) -- design captured, not implemented.
  2. curl --user argv exposure in jira_get(), symmetric to the P4 ticket exposure already fixed -- still open, noted in SESSION_2026-08-30_dry_run_and_next_steps.md.
  3. jira_type_to_p4() "Feature Request" mapping gap -- JIRA's actual "Feature Request" type falls through to the generic Problem default rather than Feature, since the case pattern only matches "new feature"*. Still open, noted in SESSION_2026-08-31_first_dry_run.md.
  4. p4 fix / P4Blog idea -- filed as job J2J-1 on the Public Depot server directly (no JIRA project for j2j itself): "Enhance to translate P4Blog from JIRA to P4 fixes." Design questions from the original session log (SESSION_2026-08-30_dry_run_and_next_steps.md) still apply.
  5. First live-fire test -- readiness blockers now cleared (bot_p4jira has admin access; both new preflight checks pass), but deliberately deferred. Recommended starting point when ready: smallest possible blast radius, e.g. -y -max 1, before removing the cap.
# Session Log: P4 Credential Redesign, New Preflight Checks, Live-Readiness Check

**Date:** 2026-09-01 (continuation of the 2026-08-31 dry-run session)
**Author:** Claude (Claude Code session)
**Requested by:** Tom Tyler

---

## Context

Continuation of `sync_jira_to_p4jobs.sh` hardening, picking up after
`SESSION_2026-08-31_first_dry_run.md` (which found and fixed the
stdout-contamination silent-data-loss bug, change 33384). Tonight's work,
in order:

1. Aligned further with the SDP Bash Coding Standard and its template.sh
   (change 33383): colorized status output (`msg_green`/`msg_yellow`/
   `msg_red`), a `LOGGING:` section in `-man` documenting the self-logging
   behavior, `-D` for full `set -x` tracing, `get_old_log_timestamp()`
   inlined from the logging.lib equivalent, and moving the `EXIT`/`SIGINT`/
   `SIGTERM` trap to the very first line of Main Program so config/lock
   failures also complete through `terminate()` (previously they bypassed
   it and skipped the final summary line). Also fixed a pre-existing
   ShellCheck warning (dead pattern alternative in the status-mapping
   `case`) while at it.
2. **Scaled back the stdout/stderr fix per feedback.** The original fix for
   the stdout-contamination bug moved `msg()`/`dbg()`/`detail()` themselves
   to stderr -- correct, but "a bit extreme" for a two-call-site problem,
   and risked complicating future color-output handling for every caller.
   Reverted those shared functions to plain stdout and instead redirect
   only the ~4 specific `detail()`/`warnmsg()` calls inside `jira_get()`
   and `map_jira_project_to_p4()` (the two functions actually captured via
   command substitution) directly to stderr (change 33388). Saved as a
   general lesson in memory: prefer narrow, call-site-specific fixes over
   changing widely-shared helpers.
3. Fixed a misleading `Limited: no (-max 5)` summary line -- showing the
   configured cap when it wasn't actually the limiting factor implied it
   applied when it didn't (change 33389).
4. **Established a version-bump policy**, per Tom's request: bump the
   script's `declare Version="X.Y.Z"` (semver) with every submit that
   touches it -- Major/Minor/Patch per the usual rules. Caught up from the
   untracked original `1.0.0` to `2.0.0` to reflect the accumulated
   breaking changes already made this week (change 33386), then continued
   bumping with each subsequent submit. Saved as a standing memory so this
   isn't forgotten in future sessions.
5. **Replaced the P4 ticket-handling mechanism entirely.** Previously the
   script read a `P4PasswdFile` into a variable and passed it via
   `P4PASSWD`. Tom asked to stop passing a ticket at all and instead
   reference a `P4CONFIG`-format file. This went through two attempts:
   - **First attempt (wrong):** tried `p4 -config <path>`. That flag does
     not exist in this `p4` client (verified directly against `p4 -h` and
     `p4 help environment` -- `P4CONFIG` is only ever a *filename* p4
     discovers via directory-walk, not an absolute-path flag). Caught this
     myself before the first submit and switched to parsing
     `P4PORT`/`P4USER`/`P4TICKETS`/`P4TRUST` out of the file and exporting
     them per-call via `env` (this working version is what actually
     shipped as change 33390 / v3.0.0) -- but several `-man`/README
     *example* commands for one-time human setup still showed the
     hallucinated `p4 -config ... trust -y` / `login`, which Tom caught
     the next message ("Yikes, I see a hallucination in there").
   - **Second attempt (correct, change 33391 / v3.1.0):** per Tom's
     specific direction, `load_p4_config()` now just exports
     `P4CONFIG="$P4ConfigFile"` (an absolute `P4CONFIG` is used directly,
     no directory-walk, and its values take precedence over the ambient
     environment) and `P4ENVIRO=/dev/null/.p4enviro` (so no personal
     `~/.p4enviro` leaks in). `p4` itself then reads
     `P4PORT`/`P4USER`/`P4TICKETS`/`P4TRUST` from the file and resolves the
     ticket from `P4TICKETS` entirely on its own -- verified every piece
     (absolute-path `P4CONFIG` behavior, `P4ENVIRO` override, the
     `TicketExpiration` ztag field and its not-logged-in empty-string case)
     against the real `p4` client before writing any code, this time.
   - Per further feedback, the script doesn't track `P4PORT`/`P4USER`
     itself at all anymore -- every `p4` call picks them up from
     `P4CONFIG` directly -- and `load_p4_config()` doesn't validate the
     file's contents beyond confirming it exists; any misconfiguration
     surfaces naturally from the preflight checks that follow, rather than
     this script re-implementing p4's own validation.
   - Also fixed the example `P4PORT` from `ssl:workshop.perforce.com:1666`
     to `public.perforce.com:1666` -- the Public Depot isn't actually
     SSL-encrypted (it's a public, read-visible server) -- and changed
     `StateDir`'s default from `${P4HOME:-/p4/1}/tmp/jira_sync` to
     `${P4TMP:-/tmp}/jira_sync` (same value on a standard SDP instance-1
     host, cleaner fallback off SDP).
6. **Added two new preflight checks**, both bailing with a clear message
   before any syncing starts rather than letting every job upsert fail
   individually:
   - `check_p4_login()` (change 33391): verifies the configured P4USER has
     a ticket with at least 60 minutes remaining, via
     `p4 -ztag -F '%TicketExpiration%' login -s`. An empty result means not
     logged in at all.
   - `check_p4_access()` (change 33393): verifies `p4 protects -m` reports
     `admin` or `super` -- confirmed directly via `p4 help job` that
     `-f` (which this script always uses, to set
     `ReportedDate`/`ModifiedBy`/`ModifiedDate`) requires `admin`.

## Live-readiness check

Tom set up a dedicated service account, `bot_p4jira`, with its own
`P4TICKETS` file, and asked directly: have we pushed anything live yet, and
do we think it'll work? Answer: no live runs yet, everything has been
`-C ... -max N -v N` with no `-y`. Checked three things live against the
Public Depot (all read-only, zero risk) to answer honestly rather than
guess:

- `p4 jobspec -o`: real field names/values match exactly what the script
  writes (`Status`/`Type` enums, `perforce-software-sdp` present in the
  `Project` enum).
- `p4 job -o SDP-1172`: came back as a blank template, confirming most/all
  of a first live run would be *creating* jobs, not updating existing
  ones -- consistent with the tool's whole premise (Public Depot jobs
  stopped tracking JIRA a while back).
- `p4 protects -m`: initially reported `write`, not `admin` -- which would
  have made every live job upsert fail on the `-f` flag. Tom granted
  `admin` access mid-session; re-checked and confirmed `admin`. This is
  exactly the gap `check_p4_access()` (above) now catches automatically.

**Net: as of this session, the identified live-readiness blocker (insufficient
P4 access) has been resolved and both new preflight checks pass. No live run
has been attempted; Tom deferred that to a future session.**

## Design note for later: `-batch` as a separate option from `-max`

Tom observed that `-max` currently always blocks watermark advancement
(true, by design -- it exists as a pilot/safety-valve cap: touch a few real
issues, and if anything's wrong, rerun the exact same ones after fixing
config rather than skipping past unreviewed data). He raised a second, 
different use case: processing a large backlog in controlled batches (e.g.
50 at a time) where the watermark *should* advance after each clean batch,
making forward progress across repeated invocations. Proposed handling this
as a new `-batch` option, mutually exclusive with `-max`, rather than
changing `-max`'s existing behavior. Captured here, not implemented yet.

Three things worth working out before building it:

1. **Needs to be a distinct, explicit flag** (not a mode of `-max`) so the
   existing pilot-cap safety property doesn't quietly change for anyone
   already using `-max` that way.
2. **The watermark-advance target differs from a normal full run.** A full
   clean run advances to `RunStartTime` (everything up to "now" has been
   verified). A batch-capped run has only verified issues up to the
   `updated` timestamp of the last issue actually processed (in the
   `ORDER BY updated ASC` stream) -- advancing to "now" would skip
   unverified issues. `-batch` mode would need to track and persist that
   last-processed timestamp instead of reusing the existing
   `RunStartTime`-based logic.
3. **Multi-project runs make this a real correctness risk, not just an
   edge case.** The watermark is one shared value across every configured
   `JiraProjects` entry. If a batch cap cuts the run short partway through
   project B, with project C not yet even queried this run, advancing the
   shared watermark to B's cutoff point would silently skip project C's
   entire unprocessed backlog between the old watermark and that cutoff --
   C's own progress was never actually verified this run. Safest options:
   (a) only support `-batch` when a single project is targeted via `-p`
   (much smaller, safer first step), or (b) move to a per-project
   watermark store (bigger change -- the watermark file becomes keyed per
   project). Lean toward (a) if/when this gets built.

## Outstanding items (not done this session)

1. **`-batch` option** (above) -- design captured, not implemented.
2. **`curl --user` argv exposure** in `jira_get()`, symmetric to the P4
   ticket exposure already fixed -- still open, noted in
   `SESSION_2026-08-30_dry_run_and_next_steps.md`.
3. **`jira_type_to_p4()` "Feature Request" mapping gap** -- JIRA's actual
   "Feature Request" type falls through to the generic `Problem` default
   rather than `Feature`, since the case pattern only matches `"new
   feature"*`. Still open, noted in `SESSION_2026-08-31_first_dry_run.md`.
4. **`p4 fix` / `P4Blog` idea** -- filed as job **J2J-1** on the Public
   Depot server directly (no JIRA project for j2j itself): "Enhance to
   translate P4Blog from JIRA to P4 fixes." Design questions from the
   original session log
   (`SESSION_2026-08-30_dry_run_and_next_steps.md`) still apply.
5. **First live-fire test** -- readiness blockers now cleared
   (`bot_p4jira` has `admin` access; both new preflight checks pass), but
   deliberately deferred. Recommended starting point when ready: smallest
   possible blast radius, e.g. `-y -max 1`, before removing the cap.
# Change User Description Committed
#1 33523 C. Thomas Tyler Renamed folder.
//j2j/dev/ai/SESSION_2026-09-01_p4_credentials_and_preflight_checks.md
#1 33394 C. Thomas Tyler Session log: P4 credential handling redesign (P4CONFIG/P4ENVIRO export, catching and fixing a p4 -config hallucination along the way), new check_p4_login()/check_p4_access() preflight checks, live-readiness check (jobspec fields confirmed, access level gap found and resolved), and design notes for a future -batch option distinct from -max.