Discussion #80: developer guides, sidebar, and the pages this made stale
New:
Email-Template-Sender-Rules-Developer-Guide
Email-Signatures-Developer-Guide
Updated because the change made them wrong, not merely incomplete:
Email-Send-Log - Result is now Sent / Failed / Not sent
Canned-Responses - [ticket_url] joins the merge code table
Tickets - sender rules and [ticket_url] on email templates
External-Issue-Trackers-Developer-Guide,
Azure-DevOps-Connector-Developer-Guide
- integrationsAbsoluteUrl now delegates to
publicAbsoluteUrl, plus the subfolder fault it had
_Sidebar - all five pages, nested under Tickets
Every internal link in the changed pages checked against a real file.
Issue trackers: Azure DevOps connector, and the contract test it settled (#964-966)
New page: Azure-DevOps-Connector-Developer-Guide, the sibling of the Jira
one. Issue-Trackers gains Azure DevOps setup and the Resolved setting;
the two guides that PREDICTED this work now record how it turned out.
The engine guide committed to a falsifiable claim before Jira shipped:
adding connector #2 must touch nothing but the provider, one registry
row and its settings partial. It held, and the page now says so with the
three things that did change for everyone:
- settings_fields, and why it is separate from credential_fields — a
dropdown among the credential boxes inherits their blanking rule and
silently resets on every save;
- integrationsAbsoluteUrl(), because the ticket link every connector
puts in an issue was built from BASE_URL, which is a path, so it 404'd
from inside any tracker and had never worked;
- $target may be keyed either way — core's neutral `issue_type` or the
provider's own word — because reading only one silently creates the
wrong kind of work item.
The Jira guide's "if you are writing the next connector" list is now
marked as validated, with two of its decisions reclassified as Jira-ONLY
now there is something to compare against:
- relative JQL dates exist because Jira reads an absolute date in the
USER's timezone. Azure DevOps honours an explicit UTC Z. Copying
either across is a bug, and both are right for their own tracker;
- flavour-dependent author_identity is an Atlassian quirk, not a general
requirement. What IS general is that it match testConnection().
What the new page records that the code cannot say for itself:
- ⚠️ which field holds the body depends on the work item TYPE. A Bug's
form shows Repro Steps and not System.Description, so writing the
description to the obvious field returns 200 and produces a work item
that looks empty to the developer who opens it;
- 🔑 five state categories, not four, and why the fifth is a per-connection
SETTING rather than a mapping — plus the live vindication of "never
branch on a status name": "Resolved" is category Resolved on a Bug and
InProgress on a User Story, same project;
- ⚠️ timePrecision=true is a query parameter, not a body field, and the
tempting fix for the error it throws silently re-reads a day of comments;
- ⚠️ echo suppression must use createdBy.id — the two endpoints report
DIFFERENT descriptor formats for the same person, so comparing those
never matches and every comment we write comes back as a developer's;
- ⚠️ attachments are two steps and step one attaches the file to nothing;
- ⚠️ a rejected token answers 203 with a sign-in page, not 401 with JSON.
Also corrected two stale rows in the analyst page's "not there yet"
table: attachments and "tell the requester when it is done" both shipped
weeks ago and were still listed as missing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Issue trackers: sending an attachment after escalation (#961)
Records why it is a button rather than automatic, and the guards on an
endpoint that takes two ids from the browser — chiefly that the
attachment must belong to that ticket, or any file in the system could
be posted to any issue.
Issue trackers: attachments proven live, and refresh the stale header
A real 83 KB PDF went from a ticket to KAN-6 and Jira reported it back
byte-identical, so 7g is no longer 'unproven live'.
The page header had drifted two releases behind: it still said tracker.*
triggers did not exist and quoted 252 assertions. Now #945-960, 288
assertions, 12/17 parity, with what is genuinely still missing listed.
Issue trackers: attachments (#960)
Gains 7g: why inline images are excluded (and what that costs), the
size/count rules, why a failed upload must never fail the escalation, and
the three Jira specifics that make an upload work — the no-check token, the
field named `file`, and a random boundary.
Also records a test lesson: asserting the bytes AROUND a sanitised
filename fails on correct output. Assert the value.
Issue trackers: tracker.* triggers (#958), and why they are not time-based
Engine guide gains 7f: the three triggers, that each carries the ticket,
the aliased columns in the payload query that are silent when wrong, and
the comment loop that terminates only because send_note_to_tracker
records what it pushes.
Time-Based Triggers gains a "a cron is not the same as time-based"
section, because reusing the emissions ledger for these is the obvious
instinct and it is wrong — a fingerprint on current state would swallow
a genuine third transition.
Issue trackers: separate the two "no change to the tickets module" claims
Escalation genuinely added nothing to the tickets module and that still
holds. The module as a whole stopped being untouched at #954, because
reading comments back means rendering them — get_notes.php, inbox.js,
inbox.css and tickets/index.php are all in it now.
Worth pinning because the stale version is exactly the sort of line that
ends up in published copy.
Issue trackers: the pretty-URL relative-path trap on the help page
Three traps worth naming, all hit within minutes of adding the page: a
pretty URL deeper than its file breaks relative asset paths (use
BASE_URL); $path_prefix must stay filesystem-relative because the system
header requires through it; and a System page must use the system
header, not the root one, or it renders the ticketing nav.
Issue trackers: the grouped routing rules and the in-app setup guide
Records why departments and companies are never one flat list (the
grouping is what makes precedence visible), and documents help.php —
including that its rewrite must precede the provider rule.
Issue trackers: document mapping (#957)
Engine guide gains 7e: the precedence rule and why it is that way round,
why priority has no wildcard, the narrow rejected-priority retry, the
namespaced local_key, and two traps — the column is ticket_type_id not
type_id, and a shared service must not assume it owns the transaction.
Analyst page gains a Mapping section in plain terms, and the Jira page
records that mapping needed no connector change beyond listPriorities(),
which is the abstraction doing its job.
Add a Scheduled tasks page; bring the tracker dev guides current
New page: Scheduled-Tasks. Ed asked for one place covering every cron
job / Windows task FreeITSM needs, because "you must schedule something
or comments never arrive" was buried in the Jira page. Covers all four
jobs, what silently breaks without each, Windows and Linux commands, how
to run one by hand, and how to tell whether they are working.
Also documents what is NOT a scheduled task, so nobody goes looking for
a job that does not exist or schedules the InTune workers, which the app
starts itself. Notes that mail is fetched by the browser, so nothing is
collected overnight with every browser closed.
Windows gotchas that cost time today: /ru SYSTEM tasks are invisible to
a non-elevated session, 0x41303 means "not yet run", and the escaped
quoting fails if a path has spaces.
Linked from Home, the sidebar, and five places in Issue-Trackers.
Dev guides brought current for #954-956: assertion count 227, range
#945-956, the pipeline diagram no longer shows the removed author
guard, and a new note on inbound_enabled — a column that shipped in V1
with no writer, so the feature it gated could never be turned on. That
is a trap worth naming for the other columns V1 shipped early.
Issue trackers: why author-based echo suppression was removed (#956)
Records the failure and the reasoning, at length, because the idea is
tempting enough that someone will reach for it again: "authored by our
account, therefore our own echo" assumes a service account that never
types, and the token owner is usually a human who comments.
Also notes the uncomfortable part — the suite was green and contained
assertions pinning the wrong behaviour, because they shared the design's
assumption. Only a live account found it.
Issue trackers: author_kind, and why "Unknown" was the wrong answer (#955)
Records the four cases a note's author can be in, and that collapsing
them into one label discards information the row holds. Also notes that
delete_analyst.php reassigns nothing, so a departed analyst's notes are
the normal case rather than an edge case.
Issue trackers: comments coming back, and the join that hid notes (#954)
The engine guide gains 7d — the inbound pipeline, both echo guards, the
"first poll imports nothing" rule and why the comment map row is written
before the note (the unique key is what wins a race between two cron
runs, not the check before it).
The Jira guide gains 7: two calls rather than one per issue, why the JQL
date must be relative (an absolute one is read in the Jira user's
timezone, not UTC), why the ADF reader lives in the connector rather
than IssueDoc, and that author_identity must match testConnection() or
echo suppression silently stops working.
The analyst page documents the toggle, that imported comments are always
internal, and that enabling it does not bring back a backlog.
Also recorded: get_notes.php inner-joined notes to their author, so 10
of 17 notes on the dev install were invisible. Both dev pages now list
what forces an update, including the rules above.
Tracker guide: correct the shipped range, point at the parity scoreboard
Issue trackers: the analyst page, and cross-links (#945-953)
The dev pair existed but the analyst page did not, so a user had no
page at all. Issue-Trackers covers setup (including the API token
living in the Atlassian account, not Jira), raising an issue, reading
the pill, automating it with a workflow rule, and an honest 'what is
not there yet' — comments coming back is named as the biggest gap
rather than left to be discovered.
Also: sidebar entry, and both dev pages now point at it.
Jira guide: the removed search endpoint, and real-Jira proof (#953)
Cloud retired /rest/api/3/search for /search/jql; DC keeps the old one.
Recorded with the lesson that generalises — a connector's correctness
depends on someone else's API, so when a call starts failing, suspect
the endpoint before the logic.
Status banner now records that the whole journey has run against a live
Jira Cloud site.
Tracker guide: the poll cron (#951)
Records that the poll is currently the ONLY way status changes, the
per-connection interval, stamping on failure, and the fetchIssues()
distinction — swallow one bad chunk, but rethrow when every chunk
failed, because [] is indistinguishable from 'those issues do not
exist' and the poll would look healthy while the tracker was down.
Tracker guides: the ticket side (#950)
§7c covers the pill in the Links strip, the manual escalate and its
preview, integrationsBodyToText (and why strip_tags alone leaves a
stylesheet in the description), and the two traps — modals open with
classList.add('active') not style.display, and inbox.js?v= must be
bumped. Both present as 'the button does nothing'.
Header no longer claims 'engine only'; status now says raising works
but nothing comes back yet and the poll cron is missing.
Bring the tracker guides up to #948 and #949
The pages documented up to #947 and then two commits shipped without
them, so §9 confidently said "not built" about the settings screen and
the workflow actions — both live. A wiki that is wrong is worse than
one that is missing, because someone trusts it.
Added: §7a the workflow surface (the two actions, the connection
lookup, argBool, and why dry-run safety lives in runInner rather than
the handler), §7b the settings screen (the folder-level .htaccess
pattern, one shared provider.php, and the four traps — .form-row being
display:flex in inbox.css, full-width needing BOTH no max-width and no
auto margin, showConfirm/showToast over browser dialogs, and closest()
once a button contains an SVG).
Updated: the file table, the §9 status table, §10 to cover the provider
registry that keeps a new tracker cheap, the contract for
pollChanges()'s watch list, and a note that the service is
self-contained because it once was not and fataled on decryptValue().
Recorded the miss itself in "keeping this page honest" — same commit,
not the next one.
External issue trackers + Jira connector developer guides (#945-947)
Two pages, split on the line that matters: the engine page is the
contract every tracker must satisfy, the Jira page is the worked
example. That split is the point — whoever writes the GitHub or Azure
DevOps connector needs to know which decisions were forced by the
contract and which were just how Jira happens to work, and both pages
say so explicitly.
Also cross-referenced from Multi-Tenancy-Developer-Guide: tracker
connections added to the connection column of the three-meanings-of-NULL
table, and the outbound twin of the membrane rule recorded next to the
inbound one.
Both pages carry a "keeping this page honest" section listing what must
be updated in the same commit as a code change.