in2-agent-server 0.20260821.185429
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +369 -0
- package/agents/plan-requirement.md +32 -0
- package/dist/campfire/configItem.js +201 -0
- package/dist/campfire/configItemDescription.js +379 -0
- package/dist/campfire/deriveFromBundle.js +1013 -0
- package/dist/cli.js +465 -0
- package/dist/core/betaFeedback.js +493 -0
- package/dist/core/chapterInstructions.js +473 -0
- package/dist/core/claudeAssets.js +61 -0
- package/dist/core/gate.js +201 -0
- package/dist/core/ids.js +9 -0
- package/dist/core/install.js +60 -0
- package/dist/core/operatorQa.js +462 -0
- package/dist/core/orgCallMeter.js +178 -0
- package/dist/core/parcels.js +1235 -0
- package/dist/core/paths.js +105 -0
- package/dist/core/phases.js +225 -0
- package/dist/core/planFile.js +251 -0
- package/dist/core/planFragments.js +119 -0
- package/dist/core/readsLog.js +398 -0
- package/dist/core/registration.js +24 -0
- package/dist/core/result.js +38 -0
- package/dist/core/resume.js +233 -0
- package/dist/core/revisionChain.js +351 -0
- package/dist/core/richText.js +61 -0
- package/dist/core/semanticHash.js +89 -0
- package/dist/core/sessionOrg.js +60 -0
- package/dist/core/sfQuery.js +19 -0
- package/dist/core/spawn.js +182 -0
- package/dist/core/supervisorContract.js +230 -0
- package/dist/core/telemetry.js +1297 -0
- package/dist/core/telemetryContext.js +154 -0
- package/dist/core/telemetrySpool.js +244 -0
- package/dist/core/transcriptUpload.js +516 -0
- package/dist/core/update.js +363 -0
- package/dist/core/viewer.js +117 -0
- package/dist/core/workspace.js +92 -0
- package/dist/core/writeGrants.js +93 -0
- package/dist/core/writebackManifest.js +92 -0
- package/dist/direct/applyLoop.js +2516 -0
- package/dist/direct/batchReport.js +510 -0
- package/dist/direct/comparatorNoise.js +75 -0
- package/dist/direct/containers.js +85 -0
- package/dist/direct/contamination.js +221 -0
- package/dist/direct/crud.js +56 -0
- package/dist/direct/destructive.js +168 -0
- package/dist/direct/knownTokens.js +94 -0
- package/dist/direct/lint.js +382 -0
- package/dist/direct/metadataSchema.generated.json +1 -0
- package/dist/direct/metadataSchema.js +179 -0
- package/dist/direct/operatorPage.js +349 -0
- package/dist/direct/orgRepo.js +1531 -0
- package/dist/direct/orgRepoSpawnCount.js +21 -0
- package/dist/direct/plannedScope.js +119 -0
- package/dist/direct/preImageTargets.js +63 -0
- package/dist/direct/refVerify.js +191 -0
- package/dist/direct/registry.js +129 -0
- package/dist/direct/removals.js +262 -0
- package/dist/direct/rollback.js +1513 -0
- package/dist/direct/rollbackRun.js +1360 -0
- package/dist/direct/sessionProjection.js +126 -0
- package/dist/direct/snapshotComparability.js +165 -0
- package/dist/direct/sourceTree.js +113 -0
- package/dist/direct/unstatedChanges.js +106 -0
- package/dist/direct/waveAssembly.js +556 -0
- package/dist/direct/waveCounts.js +19 -0
- package/dist/direct/waveDerivation.js +152 -0
- package/dist/direct/waveGrade.js +185 -0
- package/dist/index.js +90 -0
- package/dist/orgread/customFieldSnapshot.js +48 -0
- package/dist/orgread/fieldMetadata.js +178 -0
- package/dist/orgread/genericSnapshot.js +61 -0
- package/dist/orgread/layoutSnapshot.js +151 -0
- package/dist/orgread/salesforceOrgReader.js +184 -0
- package/dist/orgread/snapshotTypes.js +9 -0
- package/dist/projection/bridge.js +26 -0
- package/dist/projection/diff.js +141 -0
- package/dist/projection/mapmd.js +213 -0
- package/dist/projection/nameAmbiguity.js +106 -0
- package/dist/projection/precedent.js +136 -0
- package/dist/projection/project.js +214 -0
- package/dist/projection/scope.js +110 -0
- package/dist/projection/types.js +5 -0
- package/dist/tools/analyze.js +322 -0
- package/dist/tools/auth.js +915 -0
- package/dist/tools/campfire.js +1742 -0
- package/dist/tools/closeBatch.js +154 -0
- package/dist/tools/closeText.js +35 -0
- package/dist/tools/direct.js +1613 -0
- package/dist/tools/feedback.js +318 -0
- package/dist/tools/operator.js +287 -0
- package/dist/tools/org.js +739 -0
- package/dist/tools/phase.js +249 -0
- package/dist/tools/projection.js +172 -0
- package/dist/tools/session.js +313 -0
- package/dist/tools/update.js +82 -0
- package/dist/tools/waves.js +793 -0
- package/package.json +48 -0
- package/reference/campfire-configuration-items-guide.md +710 -0
- package/reference/deployability-cribs.md +119 -0
- package/reference/operator-voice.md +141 -0
- package/reference/org-read-cribs.md +34 -0
- package/reference/scoped-dml-interim.md +68 -0
- package/reference/supervisor-playbook.md +313 -0
- package/reference/templates.md +233 -0
- package/skills/in2-delivery/SKILL.md +322 -0
- package/skills/in2-delivery/references/campfire-configuration-items-guide.md +710 -0
- package/skills/in2-delivery/references/deployability-cribs.md +119 -0
- package/skills/in2-delivery/references/operator-voice.md +141 -0
- package/skills/in2-delivery/references/org-read-cribs.md +34 -0
- package/skills/in2-delivery/references/scoped-dml-interim.md +68 -0
- package/skills/in2-delivery/references/templates.md +233 -0
- package/skills/plan-requirement/SKILL.md +188 -0
- package/viewer/index.html +899 -0
- package/viewer/server.mjs +433 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Deployability cribs — what is provably deployable, what is DML, what is genuinely impossible
|
|
2
|
+
|
|
3
|
+
Every verdict here was proven live in the client QA org (00Dfn00000BFjbBEAT, API v67.0,
|
|
4
|
+
2026-08-14) — deployed, read back, and torn down. Nothing below is inferred from docs alone.
|
|
5
|
+
Consult this BEFORE routing a component to a manual `coverageRoute`: QA round 2 lost 12 of 17
|
|
6
|
+
manual handoffs to claims this file now refutes, and three of them shipped to the operator as
|
|
7
|
+
"no deployment can create it" — stated as platform fact, and wrong.
|
|
8
|
+
|
|
9
|
+
The rule this file exists to enforce: **you may only claim a platform limit that this file
|
|
10
|
+
already lists as impossible.** Anything else you believe undeployable is a `coverageRoute` with
|
|
11
|
+
your evidence attached (the org's own refusal, not your reasoning), never a "cannot".
|
|
12
|
+
|
|
13
|
+
## Deployable NOW through the direct tier — with the shape that actually works
|
|
14
|
+
|
|
15
|
+
**Quick action on a page layout** — `Layout` → `platformActionList`, NOT `quickActionList`.
|
|
16
|
+
The list is a WHOLE-SECTION REPLACEMENT: include every standard action you want to keep
|
|
17
|
+
(`Edit`, `Delete`… as `actionType` **StandardButton**, your action as **QuickAction**), with
|
|
18
|
+
unique, ascending, contiguous `sortOrder` from 0. The two live-verified rejection texts:
|
|
19
|
+
duplicate sortOrder → `duplicate value found: PlatformActionListId duplicates value…`; a
|
|
20
|
+
standard button typed as QuickAction → `no QuickAction named Edit found`. Both were injected
|
|
21
|
+
deliberately and reproduced character-for-character — the QA "REJECTED_BY_ORG" on this type was
|
|
22
|
+
our XML, not the platform. Also: omission does NOT revert — removing an action later means
|
|
23
|
+
re-deploying the full list minus that action, not deleting the element.
|
|
24
|
+
|
|
25
|
+
**Utility bar sizing** — a `FlexiPage` with `<type>UtilityBar</type>` named by the app's
|
|
26
|
+
`utilityBar` string. There is no `UtilityBar` metadata type. Sizing rides
|
|
27
|
+
`componentInstanceProperties` with `<type>decorator</type>`, nested
|
|
28
|
+
`flexiPageRegions > itemInstances > componentInstance` (the flat `componentInstances` shape is
|
|
29
|
+
rejected outright in v67.0), and the FlexiPage needs its `<template>`. Decorator support is
|
|
30
|
+
PER-COMPONENT and server-enforced: `notes:utilityBarNoteList`, `macros:macroUtilityItem` refuse
|
|
31
|
+
sizing, and so do components no list predicts (`runtime_sales_todo_list:…` refused live). Treat
|
|
32
|
+
"does this component take width/height" as probe-to-discover via a checkOnly validate, never as
|
|
33
|
+
known.
|
|
34
|
+
|
|
35
|
+
**Lightning record page activation** — believed permanently manual for a full QA round; it is
|
|
36
|
+
not. Org default: `CustomObject` → `actionOverrides` (`actionName` View, `formFactor` Large,
|
|
37
|
+
`type` flexipage). App/profile scope: `CustomApplication` → `profileActionOverrides` — and
|
|
38
|
+
`<profile>` is REQUIRED there (live: `Required field is missing: profile`). There is no
|
|
39
|
+
app-wide-default single element: activating "for app X" means enumerating profiles, which is a
|
|
40
|
+
scoping question for the card, not a deploy detail. `pageOrSobjectType` takes the sObject API
|
|
41
|
+
name for record pages — Salesforce's own field-table doc claiming otherwise is contradicted by
|
|
42
|
+
its own sample. Neither override is removable via destructiveChanges: retrieve, set `<type>`
|
|
43
|
+
back to `Default`, redeploy.
|
|
44
|
+
|
|
45
|
+
**Compact layout assignment** — `CustomObject`/`RecordType` → `compactLayoutAssignment`.
|
|
46
|
+
|
|
47
|
+
**Record type visibility** — permission set metadata `recordTypeVisibilities`. Two hard
|
|
48
|
+
asymmetries, both live-confirmed: a permission set cannot assign Master, and cannot set a
|
|
49
|
+
DEFAULT record type — default is Profile-only, so a requirement that includes "default RT"
|
|
50
|
+
forces the Profile route for that one facet.
|
|
51
|
+
|
|
52
|
+
**Tab visibility** — permission set `tabSettings`. Values are `Available`/`Visible` — there is
|
|
53
|
+
no `Hidden` (absence is hidden). Read-back trap: metadata `Visible` reads back through the
|
|
54
|
+
sObject surface as `DefaultOn`; a verifier string-comparing the two shapes will report a false
|
|
55
|
+
mismatch.
|
|
56
|
+
|
|
57
|
+
**Queue membership (metadata route)** — `Queue` → `queueMembers` deploys clean. Membership has
|
|
58
|
+
a second, DML route below; prefer this one when the queue itself is already in the wave.
|
|
59
|
+
|
|
60
|
+
**Lightning email template** — deployable, with one prerequisite that is NOT metadata-only:
|
|
61
|
+
the enhanced folder. `EmailTemplateFolder` as a metadata type is DEAD in practice — the CLI
|
|
62
|
+
registry aliases it to `emailfolder`, never registers its suffix, and the org rejects both type
|
|
63
|
+
names in package.xml; one CLI path even prints `EmailFolder … Created` while creating NOTHING
|
|
64
|
+
(a false success — trust only read-back). The working shape: create the folder as a `Folder`
|
|
65
|
+
sObject row (`Type='EmailTemplate'` — plain DML), then deploy the `uiType=SFX` template into
|
|
66
|
+
it. `EmailTemplateSettings.enableTemplateEnhancedFolderPref` must be true first (check it — it
|
|
67
|
+
was already true in the QA org). Keep folders flat: nested Lightning template folders are
|
|
68
|
+
broken server-side (Salesforce Known Issue a028c00000zIpaDAAS). If a suitable enhanced folder
|
|
69
|
+
already exists, the template alone IS a pure metadata deploy.
|
|
70
|
+
|
|
71
|
+
**Role** — deploys, but the XML rejects access levels below the object's OWD; author the role
|
|
72
|
+
against the org's sharing model as projected, not the requirement's wish.
|
|
73
|
+
|
|
74
|
+
## Records, not metadata — REAL, but a different write path (DML), not "impossible"
|
|
75
|
+
|
|
76
|
+
Every one of these is a plain sObject row, insertable in seconds via REST. The Metadata API not
|
|
77
|
+
carrying them does NOT make them manual — it makes them data writes. Until the toolset exposes
|
|
78
|
+
a DML write lane, these route to a Deployment Task — but the task text says "awaiting the DML
|
|
79
|
+
write path", cites this file, and NEVER claims the platform cannot do it. INTERIM: the
|
|
80
|
+
supervisor may OFFER to execute these directly, under the strict card-and-consent protocol in
|
|
81
|
+
`scoped-dml-interim.md` — that file, not this list, is the permission. The moment the lane
|
|
82
|
+
exists, this whole cluster stops being manual:
|
|
83
|
+
|
|
84
|
+
- Public group / queue membership — `GroupMember` (idempotent: duplicate insert returns the
|
|
85
|
+
existing row). A ROLE joins a group via its shadow group (`SELECT Id FROM Group WHERE
|
|
86
|
+
Type='Role' AND RelatedId='<roleId>'`; `RoleAndSubordinates` variants express the
|
|
87
|
+
"(include subordinates)" distinction — it is expressible, not a judgment call).
|
|
88
|
+
- Permission set assignment — `PermissionSetAssignment` (NOT idempotent: `DUPLICATE_VALUE` on
|
|
89
|
+
re-insert; pre-check by SOQL). PSG variant via `PermissionSetGroupId` — poll
|
|
90
|
+
`PermissionSetGroup.Status` until `Updated` first, and note a recalculating PSG WRITE-LOCKS
|
|
91
|
+
its member permission sets (`…is updating. You can make edits…when the group update
|
|
92
|
+
completes`), so the poll belongs before EVERY permission-set write whose parent is in a PSG.
|
|
93
|
+
- Field/object permissions as data — `FieldPermissions` / `ObjectPermissions` rows
|
|
94
|
+
(PermissionSet parents only; send the whole dependency chain in one payload: Edit needs Read).
|
|
95
|
+
- App visibility / custom permission grants — `SetupEntityAccess` (TabSet / CustomPermission).
|
|
96
|
+
- Role assignment to a user — `User.UserRoleId` PATCH.
|
|
97
|
+
- Custom setting VALUES — list rows are plain inserts; the ORG-DEFAULT row of a hierarchy
|
|
98
|
+
setting needs `SetupOwnerId` = the org's `00D` id EXPLICITLY. The wrong-way insert (user id)
|
|
99
|
+
SUCCEEDS SILENTLY and creates a user-scoped row — only `SetupOwner.Type` distinguishes them
|
|
100
|
+
on read-back.
|
|
101
|
+
|
|
102
|
+
## Genuinely impossible — the complete list; claim nothing beyond it
|
|
103
|
+
|
|
104
|
+
- **Grant Access Using Hierarchies** (the checkbox; custom objects only) — no API of any kind.
|
|
105
|
+
The one platform blocker inside the certified types. OWD itself (`sharingModel`) IS
|
|
106
|
+
deployable.
|
|
107
|
+
- **Queue on a master-detail child** — detail side has no Owner field. A requirement asking for
|
|
108
|
+
it is a requirement defect; say so on the card.
|
|
109
|
+
- **Notes / Macros utility panel sizing** — the components reject decorators headlessly AND in
|
|
110
|
+
App Builder.
|
|
111
|
+
|
|
112
|
+
## Two verifier rules this file adds
|
|
113
|
+
|
|
114
|
+
- **Read-back beats deploy status.** Two live false-successes: the `EmailFolder Created`
|
|
115
|
+
no-op above, and a rolled-back destructive deploy that still printed a "Deleted Source"
|
|
116
|
+
table (only the JSON `numberComponentErrors` was honest). A green deploy is a claim; the
|
|
117
|
+
read-back is the fact.
|
|
118
|
+
- **Layout API names contain spaces** (`Obj__c-My Layout Name`) — anything treating component
|
|
119
|
+
identifiers as space-free corrupts on them.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Operator voice — how the supervisor talks to the human
|
|
2
|
+
|
|
3
|
+
*The pre-approval scope sheet has its own guide — `templates.md`, beside this file: three
|
|
4
|
+
layouts, worked examples, and the fixed flag vocabulary. This file governs the words; that one
|
|
5
|
+
governs the shape.*
|
|
6
|
+
|
|
7
|
+
The operators are Salesforce consultants: fluent in record types, permission sets, validation
|
|
8
|
+
rules, App Manager — and complete strangers to this harness. Reviewing real run transcripts
|
|
9
|
+
(CF80, SM301, the Pinsley judgment tests) showed one consistent defect: the DECISIONS were
|
|
10
|
+
excellent and the VOCABULARY undercut them. "All 25 components are delivered and DIFF_VERIFIED"
|
|
11
|
+
is a triumphant sentence that reads, to its actual audience, like a warning.
|
|
12
|
+
|
|
13
|
+
## The rule: two surfaces
|
|
14
|
+
|
|
15
|
+
**Operator surfaces** — question cards, progress lines between tool calls, and the end-results
|
|
16
|
+
page. These speak *Salesforce and business outcomes*. Never: internal verdict names, pipeline
|
|
17
|
+
vocabulary, lint rule names, file paths, facet counts.
|
|
18
|
+
|
|
19
|
+
**Engineering surfaces** — evidence bundles, plan.json, verdict.json, telemetry. These keep full
|
|
20
|
+
internal precision. Nothing in this guide waters them down.
|
|
21
|
+
|
|
22
|
+
The line is the audience, not the topic: "the sharing rule needs the object to be Private" is
|
|
23
|
+
operator language (a Salesforce fact); "the sharing rule linted clean against the wave-3
|
|
24
|
+
post-image" is not (a harness fact).
|
|
25
|
+
|
|
26
|
+
## Translation table
|
|
27
|
+
|
|
28
|
+
| Internal (keep in evidence) | What the operator reads |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `DIFF_VERIFIED` | Deployed and verified — every setting matches the specification ✅ |
|
|
31
|
+
| `DELIVERED_WITH_DRIFT`, drift classified benign | Deployed and verified — Salesforce recorded a few cosmetic differences; each one checked, all harmless ✅ |
|
|
32
|
+
| `DELIVERED_WITH_DRIFT`, unclassified | Deployed; double-checking a few readings before I call it done |
|
|
33
|
+
| `REJECTED_BY_ORG` | Salesforce declined this step, so nothing from it was applied — here's why and what I recommend |
|
|
34
|
+
| `VALIDATED` (dryRunOnly) | Salesforce accepted everything in a practice run — nothing has been changed yet |
|
|
35
|
+
| `LINT_BLOCKED` | My pre-flight checks stopped this before it touched your org — fixing and retrying |
|
|
36
|
+
| `AMBIGUOUS_DELIVERY` | The change was sent but the confirmation timed out — checking the org before doing anything else |
|
|
37
|
+
| wave N | step N of M |
|
|
38
|
+
| lint / lint ladder | pre-flight checks |
|
|
39
|
+
| checkOnly | Salesforce's own validation run (changes nothing) |
|
|
40
|
+
| projection / post-image | a fresh read of what's actually in your org |
|
|
41
|
+
| evidence bundle / bundle path | "the full technical log is saved with this session" — never show the path |
|
|
42
|
+
| intent check / N facets matched | every setting was compared against the spec — (drop the numbers) |
|
|
43
|
+
| OWD / sharingModel | who can see these records by default |
|
|
44
|
+
| full-file-replace hazard | this kind of change replaces the whole page/profile, so I carry everything existing forward before touching it |
|
|
45
|
+
| coverage route / deployment task raised | this piece can't be deployed as metadata — I've logged it as a tracked to-do with exact steps |
|
|
46
|
+
| `direct_apply` returns `operatorSummary` | **relay that string** — it is the sanctioned translation of the verdict |
|
|
47
|
+
|
|
48
|
+
## Cards
|
|
49
|
+
|
|
50
|
+
Everything already right about the cards stays: exactly one recommended option, honest
|
|
51
|
+
trade-offs, business consequences, the operator's own past answers cited, and "nothing has
|
|
52
|
+
changed in your org yet" wherever true. What changes:
|
|
53
|
+
|
|
54
|
+
- **Lead with the business question in one sentence.** "Two requirements disagree about who can
|
|
55
|
+
see these records — which wins?" Mechanism, if needed at all, goes inside option descriptions,
|
|
56
|
+
one clause max.
|
|
57
|
+
- **Options are verdicts about outcomes**, not procedures: "Keep records private and the sharing
|
|
58
|
+
rule works" beats "OWD Private, sharingOwnerRules deploy".
|
|
59
|
+
- An approval card promises outcomes and safeguards, not pipeline stages: "I'll build this in
|
|
60
|
+
5 steps. Salesforce validates each step before it's applied, I verify every setting after it
|
|
61
|
+
lands, and I stop and show you anything unexpected."
|
|
62
|
+
|
|
63
|
+
## Progress lines (the operator is watching)
|
|
64
|
+
|
|
65
|
+
- The activation confirmation carries the `Live progress:` URL from the `activate_session` result
|
|
66
|
+
verbatim, framed as watch live progress here — it is the one place the operator sees the run
|
|
67
|
+
move, and a link retyped from memory points at somebody else's session.
|
|
68
|
+
- Good: "Step 2 of 5 — the fields, the tab and both queues. ✅ Deployed and verified."
|
|
69
|
+
- Good, on a snag: "Salesforce flagged one item in this step — adjusting and retrying. Nothing
|
|
70
|
+
incorrect has been applied."
|
|
71
|
+
- Bad (real transcript, from the run that made this a rule): "wave assembly copied the
|
|
72
|
+
.email-meta.xml files but dropped their sibling .email content bodies." — that sentence belongs
|
|
73
|
+
in the session log and the final technical footnote, not the live narration.
|
|
74
|
+
|
|
75
|
+
## The end-results page — it arrives rendered
|
|
76
|
+
|
|
77
|
+
`close_batch` returns `operatorPage`: the top of this page, already composed, from the same
|
|
78
|
+
persisted numbers `scope` reports. **Paste it verbatim.** Do not reorder it, do not recompose it in
|
|
79
|
+
your own words, and above all do not re-count anything in it — counting configurations by hand from
|
|
80
|
+
evidence bundles at the end of a long run is how one batch reported 205 components as 94
|
|
81
|
+
configurations and 147 built as 77.
|
|
82
|
+
|
|
83
|
+
The rendered block covers the headline, the automation rate and its bar, the summary panel, and
|
|
84
|
+
every landed configuration enumerated under the requirement that owns it. Where work is still
|
|
85
|
+
outstanding it also carries a `### Still to do` heading whose COUNT it owns — and on a fully
|
|
86
|
+
automated run nothing is left, so that heading is simply absent. The block's boundary is therefore
|
|
87
|
+
the `=== END OF BLOCK` fence `close_batch` prints beneath it, never a heading inside it.
|
|
88
|
+
|
|
89
|
+
**You write everything below the pasted block**, in this order:
|
|
90
|
+
|
|
91
|
+
1. **The manual items themselves** — one line each, with the exact Setup path, a time estimate, and
|
|
92
|
+
the confirmed Campfire task id where one exists. The `DT-#####` number is the task's Campfire
|
|
93
|
+
`Name`, which `create_campfire_deployment_tasks` does not return — read it back from the
|
|
94
|
+
consultant org (`sf_read`, `Name` in the SELECT, `WHERE External_ID__c IN (…)`). Never print a
|
|
95
|
+
raw 18-character record Id, and never invent a number.
|
|
96
|
+
2. **The Campfire line.** `close_batch` cannot read Campfire, so the rendered block says nothing
|
|
97
|
+
about it and this is yours: state how many Configuration Items were re-read successfully by their
|
|
98
|
+
external ids. A row held for delivery truth is excluded and named with its remedy — some rows
|
|
99
|
+
confirmed and some held is the normal shape, not a failure. If NO writeback happened or NO
|
|
100
|
+
read-back succeeded, write **“Not recorded in Campfire — <reason>”**; never let a zero imply a
|
|
101
|
+
verified writeback.
|
|
102
|
+
3. **Rollback**, as prose, never a status column and never a question the operator must answer at
|
|
103
|
+
every close: **“I can prepare a rollback for your approval.”** Newly created components are
|
|
104
|
+
removed to undo them; existing configuration is restorable only where a prior version was
|
|
105
|
+
captured. If any existing-state change lacks that prior version, name the limitation here.
|
|
106
|
+
4. **Optional checks** — things to tick off, specific to this batch's components. Runtime
|
|
107
|
+
verification and follow-up never inflate the manual count.
|
|
108
|
+
5. **Notes worth knowing** — two or three plain sentences: decisions the operator made and their
|
|
109
|
+
consequences, anything Salesforce normalized cosmetically, anything deferred and why.
|
|
110
|
+
6. **Details for your technical team** — verdicts per step, drift classifications with evidence
|
|
111
|
+
citations, session id, evidence locations. Everything above this line is readable without it.
|
|
112
|
+
|
|
113
|
+
If `operatorPage` comes back empty — a batch that recorded no requirement index, or a renderer that
|
|
114
|
+
failed — say what the close report shows in plain language and state that the summary could not be
|
|
115
|
+
composed. Do not reconstruct the block by hand.
|
|
116
|
+
|
|
117
|
+
### What the rendered block will not do for you
|
|
118
|
+
|
|
119
|
+
It states no Campfire count, no time estimate, and no rollback promise, because it is rendered by a
|
|
120
|
+
tool that cannot verify any of the three. Those are exactly the claims that must come from what you
|
|
121
|
+
actually observed.
|
|
122
|
+
|
|
123
|
+
## Voicing deviations
|
|
124
|
+
|
|
125
|
+
The run does not write to the requirement record, so a deviation is never composed as a note.
|
|
126
|
+
`campfire_config_item_plan`'s `requirementDisclosures` is the short, evidence-derived explanation
|
|
127
|
+
of where an observed org result differs from what was approved — and it is already carried onto
|
|
128
|
+
its own Configuration Item row by the writeback. This entry's job is spoken, not written: work
|
|
129
|
+
every non-empty disclosure into the review, in the operator's own language — under "Notes worth
|
|
130
|
+
knowing" on the end-results page, or the equivalent point in the delivery review that precedes it.
|
|
131
|
+
**Do not paraphrase it back into the approved wish** — that is the one place where operator
|
|
132
|
+
language could turn an observation into a claim, and it must not.
|
|
133
|
+
|
|
134
|
+
The writeback mechanics themselves — held rows, async settings, external-id read-back — are the
|
|
135
|
+
playbook's step 8; nothing here changes them.
|
|
136
|
+
|
|
137
|
+
## What NOT to change
|
|
138
|
+
|
|
139
|
+
Honesty is the product. Never soften a real failure, never skip an assumption on the approval
|
|
140
|
+
card, never replace a consequence with a vibe. The goal is the same rigor arriving in the
|
|
141
|
+
reader's language — a consultant who understands exactly what happened, without a glossary.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Org-read cribs — what the org's own query surfaces do and do not prove
|
|
2
|
+
|
|
3
|
+
Read this when you are doing BINDING work against a live org: establishing whether a component
|
|
4
|
+
exists, resolving its API name, or confirming what an earlier read reported. These are org-shape
|
|
5
|
+
facts, not tool instructions — nobody deciding whether to call `sf_read` needs them, and an
|
|
6
|
+
analyzer resolving a name does.
|
|
7
|
+
|
|
8
|
+
Each one is live-caught (CF79) and each cost a run.
|
|
9
|
+
|
|
10
|
+
## Never conclude ABSENCE from a context-scoped UI-API view
|
|
11
|
+
|
|
12
|
+
`AppDefinition` and `TabDefinition` are context-scoped UI-API views: they return EMPTY for rows
|
|
13
|
+
that demonstrably exist, because what they return depends on the querying user's context rather
|
|
14
|
+
than on what the org holds. A zero-row result from either proves nothing at all. If you need to
|
|
15
|
+
know whether an app or a tab exists, ask a surface that answers the question.
|
|
16
|
+
|
|
17
|
+
## The surfaces that DO answer it
|
|
18
|
+
|
|
19
|
+
- **`CustomApplication` is tooling-queryable** — `--use-tooling-api`, `DeveloperName`. That is the
|
|
20
|
+
reliable existence check for an app.
|
|
21
|
+
- **Tooling `CustomTab` returns NULL `DeveloperName` for object tabs.** That is not absence: an
|
|
22
|
+
object tab's metadata `fullName` is simply the object's API name, so there is no separate
|
|
23
|
+
developer name to return. Web and Visualforce tabs come back named correctly, so a
|
|
24
|
+
`WHERE DeveloperName != null` filter is a filter on TAB KIND, never on existence.
|
|
25
|
+
- **`FlowDefinitionView`, `ProcessDefinition` and `Group` are regular-API and reliable.** Note
|
|
26
|
+
"regular-API": routing them through the Tooling API fails on every org, and a probe failure is
|
|
27
|
+
indistinguishable from "the feature is off" — which is exactly how a sweep can silently collect
|
|
28
|
+
nothing and look like a clean answer.
|
|
29
|
+
|
|
30
|
+
## The general rule underneath all four
|
|
31
|
+
|
|
32
|
+
A read surface that can return empty for two different reasons — "it is not there" and "you cannot
|
|
33
|
+
see it from here" — cannot be used to prove the first. Pick the surface whose empty result has one
|
|
34
|
+
meaning, or state in your plan that you could not establish absence.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Scoped DML interim protocol — offering to run the record-writes instead of handing them back
|
|
2
|
+
|
|
3
|
+
INTERIM, until the pipeline grows a DML write lane. This file authorizes ONE narrow exception to
|
|
4
|
+
"never call raw `sf` mutations": the supervisor may execute the record-write mechanisms named in
|
|
5
|
+
`deployability-cribs.md` ("records, not metadata" section) directly through the CLI — ONLY after
|
|
6
|
+
the operator approves the exact rows on a card, ONLY against the session's bound target org, and
|
|
7
|
+
ONLY for the mechanisms this file carries commands for. Anything not listed here stays a manual
|
|
8
|
+
task. This protocol never expands by analogy; it expands by a new entry in this file.
|
|
9
|
+
|
|
10
|
+
## When to offer
|
|
11
|
+
|
|
12
|
+
At the point you would otherwise hand the operator a manual task whose mechanism appears in the
|
|
13
|
+
cribs' DML cluster (memberships, assignments, FLS/object-permission rows, SetupEntityAccess
|
|
14
|
+
grants, `User.UserRoleId`, custom setting VALUES, the email-template `Folder` row). Instead of
|
|
15
|
+
"you need to do this in Setup", the card says: "I can run these N record-writes for you now —
|
|
16
|
+
here is each one — or leave them as manual tasks." The operator picks per card, not per row.
|
|
17
|
+
|
|
18
|
+
## The card — consent is to the EXACT rows
|
|
19
|
+
|
|
20
|
+
The card lists every row to be written: object, field values, and the org it lands in, named the
|
|
21
|
+
way the operator knows it (the target org they authenticated at activation — NEVER the Campfire
|
|
22
|
+
org, whose writes flow only through the writeback tools). Approval covers exactly the rows on
|
|
23
|
+
the card. A row discovered after approval is a NEW card, not an extension. Decline = the manual
|
|
24
|
+
task ships as it would have anyway, with no second ask.
|
|
25
|
+
|
|
26
|
+
## Execution rules
|
|
27
|
+
|
|
28
|
+
- Resolve the CLI: `command -v sf` first, else `$IN2_HOME/tools/node_modules/.bin/sf`
|
|
29
|
+
(`IN2_HOME` defaults to `~/.in2-agent`). Always pass `--target-org <the session's target org
|
|
30
|
+
alias>` explicitly on every command — never rely on a default org.
|
|
31
|
+
- INSERTS ONLY, plus the single sanctioned PATCH (`User.UserRoleId`, current value captured on
|
|
32
|
+
the card first so it can be restored). Never update or delete a pre-existing row under this
|
|
33
|
+
protocol — a wrong edit to someone else's row is exactly the damage the write gate exists to
|
|
34
|
+
prevent, and no card can make it reversible.
|
|
35
|
+
- The probe-measured guards are MANDATORY, not advisory:
|
|
36
|
+
- `PermissionSetAssignment`: SOQL pre-check for an existing assignment first — a duplicate
|
|
37
|
+
insert throws `DUPLICATE_VALUE`; an existing row means DONE, not an error.
|
|
38
|
+
- PSG assignment (`PermissionSetGroupId`): poll `PermissionSetGroup.Status` until `Updated`
|
|
39
|
+
first — and before ANY permission-set write whose parent set belongs to a PSG (a
|
|
40
|
+
recalculating group write-locks its members).
|
|
41
|
+
- Hierarchy custom setting org default: `SetupOwnerId` = the org's `00D` id explicitly. The
|
|
42
|
+
wrong-way insert (user id) SUCCEEDS SILENTLY as a user-scoped row — read back
|
|
43
|
+
`SetupOwner.Type` and refuse to report success unless it is the org.
|
|
44
|
+
- `ObjectPermissions`: the whole dependency chain in one payload (Edit needs Read; ModifyAll
|
|
45
|
+
needs Read+Edit+Delete+ViewAll).
|
|
46
|
+
- A ROLE joining a group: resolve the shadow group (`SELECT Id FROM Group WHERE Type='Role'
|
|
47
|
+
AND RelatedId='<roleId>'`; `RoleAndSubordinates` for "(include subordinates)").
|
|
48
|
+
- Read-back is the ONLY success. Query every written row back by Id and show the Ids on the
|
|
49
|
+
result line. CLI exit 0 is a claim (two live false-success modes are on record).
|
|
50
|
+
|
|
51
|
+
## Recordkeeping — nothing about the ledger changes
|
|
52
|
+
|
|
53
|
+
- The Deployment Task for the item is still filed, then marked `Complete` with the written row
|
|
54
|
+
Ids in its description: "automated via scoped CLI with operator approval on <date>; rows:
|
|
55
|
+
<Ids>; undo: delete these Ids." The row Ids ARE the rollback plan — record them in the
|
|
56
|
+
session's notes too, because a batch rollback must delete them (GroupMember, QueueSobject and
|
|
57
|
+
SetupEntityAccess have no update verb; undo is delete).
|
|
58
|
+
- Configuration Item writeback for these rows follows whatever the mapping table supports today;
|
|
59
|
+
where the edge type has no CI convention yet, the completed Deployment Task is the record.
|
|
60
|
+
|
|
61
|
+
## Say this plainly to the operator (the honest limit)
|
|
62
|
+
|
|
63
|
+
This removes the LABOR, not yet the metric. The automation rate is computed from what the
|
|
64
|
+
approved plans own; an item routed to manual and then executed under this protocol still counts
|
|
65
|
+
on the manual side of that rate until the real DML lane makes these rows first-class planned
|
|
66
|
+
components. Do not imply the certified number improves because the operator stopped clicking —
|
|
67
|
+
the number the contract reads moves when the lane lands, and pretending otherwise is the exact
|
|
68
|
+
counting sin QA round 2 documented.
|