dsh-office-kit 0.2.0 → 0.3.0
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/CAPABILITY.md +147 -68
- package/README.md +3 -1
- package/assets/skills/excel-live-control/SKILL.md +234 -0
- package/assets/skills/excel-live-control/container_tools/live_excel.py +1589 -0
- package/assets/skills/excel-live-control/domain_guidance/financial_models.md +86 -0
- package/assets/skills/excel-live-control/domain_guidance/healthcare.md +58 -0
- package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +53 -0
- package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +53 -0
- package/assets/skills/excel-live-control/references/office-automation.md +207 -0
- package/assets/skills/excel-live-control/references/read_only_qna.md +59 -0
- package/assets/skills/excel-live-control/style_guidelines.md +87 -0
- package/assets/skills/excel-live-control/workflows/create_workflows.md +78 -0
- package/assets/skills/excel-live-control/workflows/edit_workflows.md +72 -0
- package/assets/skills/office-documents/SKILL.md +90 -77
- package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +86 -0
- package/assets/skills/office-documents/ooxml/comments.md +40 -0
- package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +66 -0
- package/assets/skills/office-documents/ooxml/rels_and_content_types.md +62 -0
- package/assets/skills/office-documents/ooxml/tracked_changes.md +53 -0
- package/assets/skills/office-documents/references/docx-structure.md +83 -0
- package/assets/skills/office-documents/references/template-elicitation.md +49 -0
- package/assets/skills/office-documents/references/writing-quality.md +49 -0
- package/assets/skills/office-documents/render_docx.py +92 -0
- package/assets/skills/office-documents/scripts/a11y_audit.py +194 -0
- package/assets/skills/office-documents/scripts/accept_tracked_changes.py +151 -0
- package/assets/skills/office-documents/scripts/add_tracked_replacements.py +148 -0
- package/assets/skills/office-documents/scripts/append_blocks.py +108 -0
- package/assets/skills/office-documents/scripts/apply_template_styles.py +104 -0
- package/assets/skills/office-documents/scripts/captions_and_crossrefs.py +102 -0
- package/assets/skills/office-documents/scripts/comments_add.py +136 -0
- package/assets/skills/office-documents/scripts/comments_apply_patch.py +114 -0
- package/assets/skills/office-documents/scripts/comments_extract.py +85 -0
- package/assets/skills/office-documents/scripts/comments_strip.py +74 -0
- package/assets/skills/office-documents/scripts/content_controls.py +192 -0
- package/assets/skills/office-documents/scripts/core_properties.py +124 -0
- package/assets/skills/office-documents/scripts/docx_kit.py +587 -0
- package/assets/skills/office-documents/scripts/docx_ooxml_patch.py +225 -0
- package/assets/skills/office-documents/scripts/docx_table_to_csv.py +99 -0
- package/assets/skills/office-documents/scripts/fields_materialize.py +66 -0
- package/assets/skills/office-documents/scripts/fields_report.py +59 -0
- package/assets/skills/office-documents/scripts/flatten_ref_fields.py +62 -0
- package/assets/skills/office-documents/scripts/footnotes_report.py +77 -0
- package/assets/skills/office-documents/scripts/google_docs_title_sanitize.py +96 -0
- package/assets/skills/office-documents/scripts/heading_audit.py +81 -0
- package/assets/skills/office-documents/scripts/images_audit.py +80 -0
- package/assets/skills/office-documents/scripts/insert_note.py +126 -0
- package/assets/skills/office-documents/scripts/insert_ref_fields.py +90 -0
- package/assets/skills/office-documents/scripts/insert_toc.py +84 -0
- package/assets/skills/office-documents/scripts/internal_nav.py +146 -0
- package/assets/skills/office-documents/scripts/make_fixtures.py +169 -0
- package/assets/skills/office-documents/scripts/merge_docx_append.py +239 -0
- package/assets/skills/office-documents/scripts/privacy_scrub.py +131 -0
- package/assets/skills/office-documents/scripts/redact_docx.py +113 -0
- package/assets/skills/office-documents/scripts/render_and_diff.py +101 -0
- package/assets/skills/office-documents/scripts/replace_text.py +154 -0
- package/assets/skills/office-documents/scripts/section_audit.py +91 -0
- package/assets/skills/office-documents/scripts/set_protection.py +92 -0
- package/assets/skills/office-documents/scripts/style_lint.py +111 -0
- package/assets/skills/office-documents/scripts/style_normalize.py +103 -0
- package/assets/skills/office-documents/scripts/table_geometry.py +167 -0
- package/assets/skills/office-documents/scripts/watermark_add.py +48 -0
- package/assets/skills/office-documents/scripts/watermark_audit_remove.py +67 -0
- package/assets/skills/office-documents/scripts/xlsx_to_docx_table.py +117 -0
- package/assets/skills/office-documents/tasks/accessibility_a11y.md +45 -0
- package/assets/skills/office-documents/tasks/captions_crossrefs.md +49 -0
- package/assets/skills/office-documents/tasks/clean_tracked_changes.md +49 -0
- package/assets/skills/office-documents/tasks/comments_manage.md +59 -0
- package/assets/skills/office-documents/tasks/compare_diff.md +40 -0
- package/assets/skills/office-documents/tasks/create_edit.md +107 -0
- package/assets/skills/office-documents/tasks/equations.md +59 -0
- package/assets/skills/office-documents/tasks/fields_update.md +44 -0
- package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +50 -0
- package/assets/skills/office-documents/tasks/footnotes_endnotes.md +38 -0
- package/assets/skills/office-documents/tasks/forms_content_controls.md +48 -0
- package/assets/skills/office-documents/tasks/headings_numbering.md +55 -0
- package/assets/skills/office-documents/tasks/images_figures.md +63 -0
- package/assets/skills/office-documents/tasks/multi_doc_merge.md +43 -0
- package/assets/skills/office-documents/tasks/navigation_internal_links.md +38 -0
- package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +45 -0
- package/assets/skills/office-documents/tasks/protection_restrict_editing.md +41 -0
- package/assets/skills/office-documents/tasks/read_review.md +50 -0
- package/assets/skills/office-documents/tasks/redaction_anonymization.md +42 -0
- package/assets/skills/office-documents/tasks/sections_layout.md +54 -0
- package/assets/skills/office-documents/tasks/style_lint_normalize.md +44 -0
- package/assets/skills/office-documents/tasks/tables_spreadsheets.md +64 -0
- package/assets/skills/office-documents/tasks/templates_style_packs.md +53 -0
- package/assets/skills/office-documents/tasks/toc_workflow.md +39 -0
- package/assets/skills/office-documents/tasks/verify_render.md +50 -0
- package/assets/skills/office-documents/tasks/watermarks_background.md +35 -0
- package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +47 -0
- package/assets/skills/office-documents/troubleshooting/run_splitting.md +36 -0
- package/assets/skills/office-pdf/SKILL.md +73 -56
- package/assets/skills/office-pdf/references/form-fields.md +56 -0
- package/assets/skills/office-pdf/references/geometry.md +44 -0
- package/assets/skills/office-pdf/references/layout-quality.md +41 -0
- package/assets/skills/office-pdf/references/limits.md +58 -0
- package/assets/skills/office-pdf/scripts/extract_text.py +172 -0
- package/assets/skills/office-pdf/scripts/forms.py +556 -0
- package/assets/skills/office-pdf/scripts/metadata.py +161 -0
- package/assets/skills/office-pdf/scripts/page_ops.py +198 -0
- package/assets/skills/office-pdf/scripts/redact_region.py +347 -0
- package/assets/skills/office-pdf/scripts/render_pages.py +207 -0
- package/assets/skills/office-pdf/scripts/split_pages.py +155 -0
- package/assets/skills/office-pdf/scripts/stamp_overlay.py +199 -0
- package/assets/skills/office-pdf/tasks/annotations.md +98 -0
- package/assets/skills/office-pdf/tasks/create.md +75 -0
- package/assets/skills/office-pdf/tasks/edit-pages.md +71 -0
- package/assets/skills/office-pdf/tasks/forms.md +67 -0
- package/assets/skills/office-pdf/tasks/read.md +62 -0
- package/assets/skills/office-pdf/tasks/redact.md +72 -0
- package/assets/skills/office-pdf/tasks/stamp.md +60 -0
- package/assets/skills/office-presentations/SKILL.md +141 -87
- package/assets/skills/office-presentations/container_tools/add_slides.py +136 -0
- package/assets/skills/office-presentations/container_tools/core_properties.py +120 -0
- package/assets/skills/office-presentations/container_tools/create_montage.py +126 -0
- package/assets/skills/office-presentations/container_tools/inspect_presentation_layout_geometry.py +285 -0
- package/assets/skills/office-presentations/container_tools/inspect_presentation_package_integrity.py +157 -0
- package/assets/skills/office-presentations/container_tools/native_chart_title_gate.py +144 -0
- package/assets/skills/office-presentations/container_tools/native_quantitative_chart_gate.py +199 -0
- package/assets/skills/office-presentations/container_tools/native_table_arithmetic_gate.py +212 -0
- package/assets/skills/office-presentations/container_tools/ooxml_helpers.py +345 -0
- package/assets/skills/office-presentations/container_tools/preview_render.py +375 -0
- package/assets/skills/office-presentations/container_tools/render_slides.py +139 -0
- package/assets/skills/office-presentations/container_tools/replace_text.py +168 -0
- package/assets/skills/office-presentations/container_tools/template_source_fidelity_gate.py +229 -0
- package/assets/skills/office-presentations/domain_guidance/finance.md +66 -0
- package/assets/skills/office-presentations/recipes/README.md +71 -0
- package/assets/skills/office-presentations/recipes/autolayout.md +88 -0
- package/assets/skills/office-presentations/recipes/connectors.md +83 -0
- package/assets/skills/office-presentations/recipes/images.md +80 -0
- package/assets/skills/office-presentations/recipes/master-and-layouts.md +127 -0
- package/assets/skills/office-presentations/recipes/native-charts.md +87 -0
- package/assets/skills/office-presentations/recipes/rich-text-runs.md +86 -0
- package/assets/skills/office-presentations/recipes/speaker-notes.md +65 -0
- package/assets/skills/office-presentations/recipes/tables.md +88 -0
- package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +71 -0
- package/assets/skills/office-presentations/recipes/theme-tokens.md +87 -0
- package/assets/skills/office-presentations/references/authoring-workflow.md +65 -0
- package/assets/skills/office-presentations/references/finalization.md +63 -0
- package/assets/skills/office-presentations/references/native-bullets.md +78 -0
- package/assets/skills/office-presentations/references/native-evidence.md +67 -0
- package/assets/skills/office-presentations/references/style-guidelines.md +66 -0
- package/assets/skills/office-presentations/references/templates.md +76 -0
- package/assets/skills/office-presentations/routing/google_slides.md +45 -0
- package/assets/skills/office-presentations/tasks/apply-annotations.md +83 -0
- package/assets/skills/office-presentations/tasks/charts-tables-notes.md +79 -0
- package/assets/skills/office-presentations/tasks/create-deck.md +106 -0
- package/assets/skills/office-presentations/tasks/edit-deck.md +93 -0
- package/assets/skills/office-presentations/tasks/inspect-and-verify.md +107 -0
- package/assets/skills/office-presentations/tasks/template-following.md +132 -0
- package/assets/skills/office-presentations/template_following_scripts/check_template_fidelity.py +176 -0
- package/assets/skills/office-presentations/template_following_scripts/inspect_template_deck.py +154 -0
- package/assets/skills/office-presentations/template_following_scripts/make_contact_sheet.py +111 -0
- package/assets/skills/office-presentations/template_following_scripts/prepare_template_starter_deck.py +239 -0
- package/assets/skills/office-presentations/template_following_scripts/validate_template_plan.py +185 -0
- package/assets/skills/office-spreadsheets/SKILL.md +105 -101
- package/assets/skills/office-spreadsheets/container_tools/add_chart.py +236 -0
- package/assets/skills/office-spreadsheets/container_tools/add_image.py +107 -0
- package/assets/skills/office-spreadsheets/container_tools/append_rows.py +122 -0
- package/assets/skills/office-spreadsheets/container_tools/diff_workbooks.py +306 -0
- package/assets/skills/office-spreadsheets/container_tools/inspect_workbook.py +398 -0
- package/assets/skills/office-spreadsheets/container_tools/recalc_gate.py +275 -0
- package/assets/skills/office-spreadsheets/container_tools/set_cells.py +135 -0
- package/assets/skills/office-spreadsheets/container_tools/sheet_ops.py +134 -0
- package/assets/skills/office-spreadsheets/container_tools/style_cells.py +133 -0
- package/assets/skills/office-spreadsheets/recipes/charts.md +66 -0
- package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +69 -0
- package/assets/skills/office-spreadsheets/recipes/data-tables.md +58 -0
- package/assets/skills/office-spreadsheets/recipes/named-ranges.md +41 -0
- package/assets/skills/office-spreadsheets/recipes/number-formats.md +72 -0
- package/assets/skills/office-spreadsheets/recipes/sparklines.md +43 -0
- package/assets/skills/office-spreadsheets/references/charts.md +63 -0
- package/assets/skills/office-spreadsheets/references/domain/financial-models.md +40 -0
- package/assets/skills/office-spreadsheets/references/domain/healthcare.md +22 -0
- package/assets/skills/office-spreadsheets/references/domain/marketing.md +28 -0
- package/assets/skills/office-spreadsheets/references/domain/research.md +22 -0
- package/assets/skills/office-spreadsheets/references/formula-patterns.md +78 -0
- package/assets/skills/office-spreadsheets/references/style-guidelines.md +69 -0
- package/assets/skills/office-spreadsheets/references/workbook-structure.md +60 -0
- package/assets/skills/office-spreadsheets/routing/google-sheets.md +36 -0
- package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +37 -0
- package/assets/skills/office-spreadsheets/tasks/annotations.md +51 -0
- package/assets/skills/office-spreadsheets/tasks/create-workbook.md +66 -0
- package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +38 -0
- package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +69 -0
- package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +38 -0
- package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +57 -0
- package/assets/skills/shared/annotation-recipes.md +252 -0
- package/assets/skills/shared/check_runtime.py +253 -0
- package/assets/skills/shared/common-workflow.md +139 -0
- package/assets/skills/shared/scripts/ensure_raster_image.py +187 -0
- package/dist/client.js +4 -4
- package/dist/client.js.map +1 -1
- package/dist/index.js +239 -89
- package/package.json +1 -1
- package/postinstall.mjs +92 -82
- package/python/office_cli.py +171 -246
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Financial models
|
|
2
|
+
|
|
3
|
+
Financial modelling has a short list of distinctions that decide whether a sheet is
|
|
4
|
+
right, and a live edit makes each of them visible to a user who is watching.
|
|
5
|
+
|
|
6
|
+
## The distinctions that matter
|
|
7
|
+
|
|
8
|
+
| Looks similar | Actually different |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| Revenue (earned) | Collections (cash received) — timing, bad debt, deferred revenue |
|
|
11
|
+
| Payroll expense | Cash paid to employees — accruals, timing, employer costs |
|
|
12
|
+
| Capex | Depreciation / amortisation — cash out once, expense over life |
|
|
13
|
+
| Earnings | Cash flow — working capital, non-cash items, financing |
|
|
14
|
+
| Budget | Forecast — one is a target, the other an expectation; never mix them silently |
|
|
15
|
+
|
|
16
|
+
Also, before typing a number: which fiscal calendar, which horizon (monthly / quarterly /
|
|
17
|
+
annual), and which grain (total company, segment, product)? A number without those three
|
|
18
|
+
is not a model input.
|
|
19
|
+
|
|
20
|
+
Actuals and forecast must be visibly different (a divide, a label, a different fill). The
|
|
21
|
+
reader has to know where history stops.
|
|
22
|
+
|
|
23
|
+
## Schedules
|
|
24
|
+
|
|
25
|
+
Build a driver schedule per line, then a statement, then the output. Each step is a range
|
|
26
|
+
the user can audit:
|
|
27
|
+
|
|
28
|
+
- **Revenue**: volume × price, with mix if there are segments; recognition timing if
|
|
29
|
+
contracts span periods. Do not model revenue as a straight growth percentage unless the
|
|
30
|
+
user asked for that — it hides the drivers.
|
|
31
|
+
- **Payroll**: headcount, FTE and paid FTE are three different numbers. Prorate hires and
|
|
32
|
+
exits by month; do not divide an annual salary by 12 twice (an annual figure already
|
|
33
|
+
contains the monthly rate); make the commission and employer-cost basis explicit.
|
|
34
|
+
- **Opex**: units × rate, fixed amounts, or one-time costs — say which. A growing opex line
|
|
35
|
+
needs a driver, not a percent of revenue, unless that is the stated policy.
|
|
36
|
+
- **D&A**: cost, residual value, in-service date, useful life, convention. Reconcile gross
|
|
37
|
+
asset and accumulated depreciation roll-forwards to the prior period.
|
|
38
|
+
- **Statements**: retained earnings rolls from opening + net income − dividends; the
|
|
39
|
+
cash-flow statement's ending cash equals the balance sheet's cash. If it does not, there
|
|
40
|
+
is a plug, and a plug is a finding, not a fix.
|
|
41
|
+
|
|
42
|
+
A worked unit check, done in the cells: actual salary cost $60,000 across 10 paid FTE is
|
|
43
|
+
$6,000 per FTE; a forecast of $6,300 per FTE on 11 FTE gives $69,300 against $66,000 for
|
|
44
|
+
the prior per-FTE rate — the difference is rate *and* headcount, and both drivers belong
|
|
45
|
+
on separate rows. If either missing pay or zero FTE is in the source, the implied rate
|
|
46
|
+
cannot be established; mark it unavailable, do not divide by zero and call it 0.
|
|
47
|
+
|
|
48
|
+
## Refreshes and merges
|
|
49
|
+
|
|
50
|
+
A refresh merges complete periods on the business key (a date that exists in the calendar,
|
|
51
|
+
a product code that exists in the master). Never append a partial period as if it were
|
|
52
|
+
complete, and never let a merge drop a dimension silently — report rows that did not match.
|
|
53
|
+
|
|
54
|
+
## Variances and audit
|
|
55
|
+
|
|
56
|
+
- Variances need an amount **and** a percent. When the base is zero or missing, the percent
|
|
57
|
+
is unavailable — write `n.a.`, not `0%`.
|
|
58
|
+
- Check totals: parts sum to the whole, schedules tie to statements, the bridge closes to
|
|
59
|
+
zero. Compare to two decimals, including `0.00`; a check that passes at 0.01 is not
|
|
60
|
+
passing.
|
|
61
|
+
- Failed checks: light red fill (`#FFC7CE`) with bold red text (`#9C0006`), neutral for
|
|
62
|
+
passes. Missing or untested data is "unavailable", never "PASS".
|
|
63
|
+
|
|
64
|
+
## Valuation, if it comes up
|
|
65
|
+
|
|
66
|
+
- Build the method the user asked for. A DCF needs drivers, tax, D&A, capex, working
|
|
67
|
+
capital, unlevered free cash flow, the discounting convention, a terminal value method
|
|
68
|
+
and the enterprise-to-equity bridge — skipping two of these is not a shortcut, it is a
|
|
69
|
+
wrong answer.
|
|
70
|
+
- IRR/XIRR need cash flows with valid signs and dates; a series with no sign change has no
|
|
71
|
+
IRR, and the function returning `#NUM!` is the correct answer to report.
|
|
72
|
+
- Sensitivities the user asks for belong in a native what-if data table, not in a grid of
|
|
73
|
+
hand-typed scenarios that will drift.
|
|
74
|
+
|
|
75
|
+
## Doing it live
|
|
76
|
+
|
|
77
|
+
- Read the workbook before you model: `info` for tabs and objects, then
|
|
78
|
+
`read_range --formulas` across the rows you are extending. Match the existing anchoring
|
|
79
|
+
(`$C$4` for a rate, `C$9` for a period header) and the existing aggregation style
|
|
80
|
+
(`SUMIFS` over hand-rolled sums).
|
|
81
|
+
- Add one driver row at a time, each with a formula you can point at, and verify after each
|
|
82
|
+
block; a 200-cell scenario grid written blind is the expensive way to fail.
|
|
83
|
+
- If the model has a check tab, extend the checks to cover your new rows. If it has none
|
|
84
|
+
and the model is small, add one labelled verification row next to the output.
|
|
85
|
+
- Never write a hard-coded total when a formula can tie it. And never "fix" an existing
|
|
86
|
+
`#REF!` — report it.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Healthcare
|
|
2
|
+
|
|
3
|
+
Two kinds of workbook live in a health organisation, and they carry different rules:
|
|
4
|
+
|
|
5
|
+
- **Clinical and patient records**: appointments, encounters, observations, results.
|
|
6
|
+
The source of truth is a clinical system; a workbook holds an extract.
|
|
7
|
+
- **Administrative and financial work**: budgets, staffing, throughput, cost per case.
|
|
8
|
+
Money follows `financial_models.md` even when the organisation is a hospital.
|
|
9
|
+
|
|
10
|
+
Most healthcare spreadsheet tasks are the second kind built on top of the first. Keep the
|
|
11
|
+
extract and the analysis visibly separate.
|
|
12
|
+
|
|
13
|
+
## Handling the raw extract
|
|
14
|
+
|
|
15
|
+
- Put raw data on its own sheet or block, untouched, one table. Everything you compute
|
|
16
|
+
lives *beside* it or in a separate prepared block — never by overwriting a measurement.
|
|
17
|
+
- Descriptive names help the next reader: `Appointments_RawData` beats `Sheet2`;
|
|
18
|
+
`Clinic KPI Dashboard` beats `Sheet5`.
|
|
19
|
+
- Keep the source's definitions with the data: the period it covers, the extract date, the
|
|
20
|
+
source system, the denominator used. Length of stay, readmission rate and utilisation
|
|
21
|
+
are meaningless without them, and definitions differ between systems.
|
|
22
|
+
- Preserve identifiers exactly as supplied (MRN formats vary), and keep dates as dates with
|
|
23
|
+
one format down the column.
|
|
24
|
+
- Units belong in the header (`Weight (kg)`, `Temperature (°C)`, `HbA1c (%)`, `Heart rate
|
|
25
|
+
(bpm)`), not in the cells as text. A column of `"72 bpm"` strings cannot be averaged.
|
|
26
|
+
|
|
27
|
+
## Building on it
|
|
28
|
+
|
|
29
|
+
- Highlight the fields staff must complete (amber fill) and keep unused placeholders out.
|
|
30
|
+
- If a threshold drives a flag, use one named cell for it (`BMI_threshold`) and reference
|
|
31
|
+
it, so the cut-off is visible and changeable. A number buried in a formula is an
|
|
32
|
+
invisible policy.
|
|
33
|
+
- Flags come only from a stated source or protocol threshold, and keep the severity the
|
|
34
|
+
source gives (normal / elevated / high), with a legend on the sheet. Do not invent
|
|
35
|
+
clinical ranges, do not round a borderline value into a category.
|
|
36
|
+
- A codebook (code → meaning, units, abbreviations) next to the data when the extract uses
|
|
37
|
+
codes, or a legend when it uses abbreviations.
|
|
38
|
+
- Keep a `Corrected value` column or an audit log for corrections. Never edit the original
|
|
39
|
+
measurement in place; the original and the correction are both evidence.
|
|
40
|
+
|
|
41
|
+
## Consequences of getting it wrong
|
|
42
|
+
|
|
43
|
+
Clinical arithmetic and clinical judgement are different things. Compute what the source
|
|
44
|
+
supports; verify a critical calculation (dosing, risk score, threshold classification)
|
|
45
|
+
against the authoritative definition when one is available, and if it is not available say
|
|
46
|
+
so instead of asserting the number is right. Do not give clinical advice, and do not
|
|
47
|
+
present a screening flag as a diagnosis.
|
|
48
|
+
|
|
49
|
+
## Doing it live
|
|
50
|
+
|
|
51
|
+
- The user may have the extract open with their own formatting. Read before writing:
|
|
52
|
+
`info` for the sheets and used ranges, `read_range --formulas --display` for the block
|
|
53
|
+
you are extending.
|
|
54
|
+
- Add derived columns to the right of the raw block with a clear header, or to a separate
|
|
55
|
+
prepared area; never insert a column into the middle of an extract that other formulas
|
|
56
|
+
or a pivot already reference.
|
|
57
|
+
- After writing, verify with `read_range --formulas` and check the `errors` array — a
|
|
58
|
+
healthcare sheet with a `#DIV/0!` in a rate column is a report that will be misread.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Marketing and advertising
|
|
2
|
+
|
|
3
|
+
Campaign, funnel, lead, CRM and ad-performance data. The failures here are almost always
|
|
4
|
+
grain, denominator or freshness — not arithmetic.
|
|
5
|
+
|
|
6
|
+
## Know what the export is
|
|
7
|
+
|
|
8
|
+
- **Extract freshness vs analysis time.** An export pulled Tuesday and analysed Friday is
|
|
9
|
+
Tuesday's data. Record the extract date and the as-of date once, in the input area, and
|
|
10
|
+
do not compare a Friday figure with a Tuesday one as if the difference were performance.
|
|
11
|
+
- **Channel setup.** A campaign may be split across an ad platform, a CRM and a billing
|
|
12
|
+
system. Name which one each figure comes from before combining them.
|
|
13
|
+
- **Grain.** Daily rows are not campaign rows. Impressions are not sessions; clicks are not
|
|
14
|
+
leads; leads are not qualified leads; a pipeline total is not revenue.
|
|
15
|
+
- **Denominators.** CTR uses impressions, CVR uses sessions or clicks depending on the
|
|
16
|
+
platform's definition, CPA uses conversions attributed that period. Carry the platform's
|
|
17
|
+
definition into the label; two vendors' "conversion rate" differ.
|
|
18
|
+
|
|
19
|
+
## Layout
|
|
20
|
+
|
|
21
|
+
- Name tabs by content and period: `Leads_Q1_2025`, `Pipeline Analysis`, `ROI Dashboard`.
|
|
22
|
+
- Keep the raw import intact on its own sheet; clean in derived columns or a prepared
|
|
23
|
+
area, and record what you excluded or mapped (non-target region, test account,
|
|
24
|
+
renamed source) so the exclusion is visible.
|
|
25
|
+
- One typed time-series date column with one format. Add an ISO helper column only when a
|
|
26
|
+
downstream import needs it, and label it as such.
|
|
27
|
+
- Targets and traffic lights only when the source supplies a target and a direction. No
|
|
28
|
+
invented targets, no green/amber/red on numbers nobody set a goal for.
|
|
29
|
+
- Every dashboard figure traces back to a cell in the prepared data. If a number cannot be
|
|
30
|
+
traced, it does not go on the dashboard.
|
|
31
|
+
|
|
32
|
+
## Metrics
|
|
33
|
+
|
|
34
|
+
- Define abbreviations where they are used (CPC, CPM, CPA, ROAS, MQL) — a legend on the
|
|
35
|
+
analysis sheet, not a glossary tab nobody opens.
|
|
36
|
+
- Keep the comparison basis visible: week over week, month over month, or the same period
|
|
37
|
+
last year. Mixing bases across one chart is the most common misleading dashboard.
|
|
38
|
+
- Attribution: say which model (last click, first click, linear, platform-reported) and
|
|
39
|
+
keep it consistent within a table. Platform-reported and analytics-reported conversions
|
|
40
|
+
never reconcile exactly; report both rather than forcing a match.
|
|
41
|
+
- Charts only when they make a trend, a comparison or a funnel clearer than a table. A
|
|
42
|
+
chart of six categories is a table with extra steps.
|
|
43
|
+
|
|
44
|
+
## Doing it live
|
|
45
|
+
|
|
46
|
+
- Read first: `info` (which sheets, which used ranges, whether the user is mid-edit) then
|
|
47
|
+
`read_range --formulas` across the block you will extend.
|
|
48
|
+
- Append new periods as rows below the existing table and extend the table/conditional
|
|
49
|
+
formatting/chart source with it. Do not create a second table beside the first.
|
|
50
|
+
- When a figure must be flagged for refresh (stale extract, missing platform), use the
|
|
51
|
+
amber input fill and a note in the cell beside it, not a colour nobody explained.
|
|
52
|
+
- Verify with `read_range --formulas`: this is where a misaligned denominator shows up as a
|
|
53
|
+
rate that is off by a factor of ten.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Scientific research data
|
|
2
|
+
|
|
3
|
+
The spreadsheet is often the only record of an experiment. Treat the observations as
|
|
4
|
+
irreplaceable: a cleaned value that overwrote a raw measurement is data loss, and a live
|
|
5
|
+
edit is one keystroke away from it.
|
|
6
|
+
|
|
7
|
+
## Keep the raw table raw
|
|
8
|
+
|
|
9
|
+
- One flat table: one row per observation, one variable per column, one unit per column.
|
|
10
|
+
No merged cells, no multi-row headers, no calculation rows mixed into the data block.
|
|
11
|
+
- Do not overwrite a measurement. Transformations live in separate columns (clearly headed
|
|
12
|
+
`log10(x)`, `normalised`) or in a separate processed block/sheet.
|
|
13
|
+
- Record the cleaning: which rows were excluded and why, which values were imputed, which
|
|
14
|
+
units were converted. A protocol note on the sheet or a short note beside the block.
|
|
15
|
+
- Missing observations stay visibly missing (blank or `n.a.` as the table's convention
|
|
16
|
+
dictates) — never silently zero-filled. Randomised and simulated values are labelled as
|
|
17
|
+
such; they are not observations.
|
|
18
|
+
|
|
19
|
+
## Presentation tables are a different object
|
|
20
|
+
|
|
21
|
+
When the sheet is a report of the data rather than the data itself:
|
|
22
|
+
|
|
23
|
+
- One type of data per column, units in the header (`Concentration (mg/L)`), never inside
|
|
24
|
+
the cell.
|
|
25
|
+
- Never encode meaning only in colour or bold — add a labelled value column (`Flag:
|
|
26
|
+
excluded`, `Status: control`). A reader with a monochrome printout must still get the
|
|
27
|
+
full information.
|
|
28
|
+
- Notes belong in a notes column, not in cell comments that a co-author will never see.
|
|
29
|
+
- No merged cells in a table you expect anyone to sort or filter.
|
|
30
|
+
|
|
31
|
+
## Analysis
|
|
32
|
+
|
|
33
|
+
- Prefer a transparent formula to a clever one. Someone has to defend this number in a
|
|
34
|
+
review six months from now.
|
|
35
|
+
- Show the calculation steps: the intermediate columns are the evidence. Hiding them in a
|
|
36
|
+
single formula makes the result unfalsifiable.
|
|
37
|
+
- A circular reference or iterative calculation is off-limits unless the user asks for it
|
|
38
|
+
and documents it. A simulation's random seed and method are part of the result.
|
|
39
|
+
- Distinguish measurement, derived value, flag and assumption — by label, not by font
|
|
40
|
+
colour alone.
|
|
41
|
+
- If the design of the analysis changes (an exclusion added, a normalisation changed), say
|
|
42
|
+
so in the reply. A quiet change to a denominator rewrites the conclusion.
|
|
43
|
+
|
|
44
|
+
## Doing it live
|
|
45
|
+
|
|
46
|
+
- Before touching anything: `info`, then `read_range --formulas --display` on the block.
|
|
47
|
+
Raw data and report blocks are usually on different sheets; confirm which is which.
|
|
48
|
+
- Append observations as rows at the bottom of the table, extend any table object to cover
|
|
49
|
+
them, and keep the header row exactly as it is.
|
|
50
|
+
- Verify with `read_range --formulas`; the `errors` array catches the `#DIV/0!` and
|
|
51
|
+
`#VALUE!` that appear when a text value lands in a numeric column.
|
|
52
|
+
- Never delete rows from the middle of a data table; a delete shifts every downstream
|
|
53
|
+
formula and every chart range with it.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# The COM object model behind a live edit
|
|
2
|
+
|
|
3
|
+
What this skill talks to is not a file. It is an out-of-process COM server that happens
|
|
4
|
+
to own a window: every property read and every write is a remote call across process
|
|
5
|
+
boundaries, and every object you hold is a proxy that re-reads state when you ask it.
|
|
6
|
+
That explains most of the rules below.
|
|
7
|
+
|
|
8
|
+
`container_tools/live_excel.py` wraps the common cases. Read this when the CLI has no verb
|
|
9
|
+
for what the task needs, when a call fails in a way the JSON does not explain, or when you
|
|
10
|
+
are extending the tool.
|
|
11
|
+
|
|
12
|
+
## Reaching the running instance
|
|
13
|
+
|
|
14
|
+
```powershell
|
|
15
|
+
$app = [Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application')
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- This is the only supported way to find a *running* instance. `New-Object -ComObject
|
|
19
|
+
Excel.Application` creates a new, invisible one — never do that for user work.
|
|
20
|
+
- It exists in Windows PowerShell 5.1 (`powershell.exe`). PowerShell 7 (`pwsh`) removed
|
|
21
|
+
the method, which is why the tool shells out to `powershell.exe` and not `pwsh`.
|
|
22
|
+
- With nothing running it raises `0x800401E3 (MK_E_UNAVAILABLE)`. That is the signal to
|
|
23
|
+
ask the user to open the workbook, not to launch anything.
|
|
24
|
+
- WPS Spreadsheets registers both `Ket.Application` and `Excel.Application`, so a
|
|
25
|
+
successful attach to `Excel.Application` does not prove Microsoft Excel is running.
|
|
26
|
+
`Application.Name` and `Application.Version` are worse than useless here — WPS reports
|
|
27
|
+
`Microsoft Excel` / `12.0`. Infer the product from `Application.Path`.
|
|
28
|
+
- The running-object table is per user session and survives the process that created the
|
|
29
|
+
instance. A hidden instance launched for a self-test stays attachable from later calls;
|
|
30
|
+
it stays invisible until something shows it, and it leaks until `Application.Quit()`.
|
|
31
|
+
|
|
32
|
+
## Addressing
|
|
33
|
+
|
|
34
|
+
`Application` → `Workbooks` → `Workbook` → `Sheets` → `Worksheet` → `Range`.
|
|
35
|
+
|
|
36
|
+
- Collections are **1-based**: `$book.Sheets.Item(1)`. `Item(0)` throws.
|
|
37
|
+
- `$sheet.Cells` is the whole sheet; `$sheet.UsedRange` is the rectangle that has content
|
|
38
|
+
or formatting. `UsedRange` is not trimmed by deleting a value in its last cell; treat
|
|
39
|
+
it as a hint for what to read, never as the boundary of an edit.
|
|
40
|
+
- A1 strings: `A1`, `B4:D9`, `$B$14`, `Sheet1!A1:C9`, `'Build Detail'!E14` (quote sheet
|
|
41
|
+
names containing spaces). `Range.Address($row_absolute, $column_absolute)` prints one
|
|
42
|
+
back, e.g. `$r.Address(0,0)` gives `A1:C3`. Prefer reporting the absolute form the user
|
|
43
|
+
can paste into the Name Box.
|
|
44
|
+
- Sheet names are case-insensitive in .NET-side matching but must match for COM:
|
|
45
|
+
`$book.Sheets.Item('Build')` throws on `build`. Use `Worksheet.Name` for the exact
|
|
46
|
+
spelling.
|
|
47
|
+
- Multi-area ranges (`A1:A5,C1:C5`) exist; the tool refuses them for writes because a
|
|
48
|
+
rectangular `Value2` assignment cannot fill them.
|
|
49
|
+
|
|
50
|
+
## Cells: what you write and what comes back
|
|
51
|
+
|
|
52
|
+
| Property | Use it for | Reads back |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| `Range.Value2` | every value: numbers, text, dates (as serials), booleans, arrays | typed scalars / `Object[,]` |
|
|
55
|
+
| `Range.Formula` | formulas in A1 notation; also the way to read them back | `String`, e.g. `=SUM(B2:B9)` |
|
|
56
|
+
| `Range.FormulaR1C1` | fills where you think in offsets | `String` |
|
|
57
|
+
| `Range.Text` | the *displayed* string (after number format) | per-cell only |
|
|
58
|
+
|
|
59
|
+
- **`Value2` is type-preserving and locale-blind.** Assign a `Double` and the cell is a
|
|
60
|
+
number; assign a `String` and it is text — except that the application may *parse* a
|
|
61
|
+
string that looks like a date, a currency amount, or `=1+1`. Writing `"2026-01-31"`
|
|
62
|
+
through `Value2` produced the serial `46053` in a date-formatted cell. If the user meant
|
|
63
|
+
the literal text, store the serial (or the number) and set a number format, or prefix
|
|
64
|
+
the apostrophe; do not rely on the parse.
|
|
65
|
+
- **`$null` empties a cell.** That is the supported way to clear one value inside a block
|
|
66
|
+
you are writing.
|
|
67
|
+
- A multi-cell read returns a 2-D `Object[,]` with **1-based** indices. A single cell
|
|
68
|
+
returns a scalar, so code that always indexes `[1,1]` fails on one-cell ranges.
|
|
69
|
+
- **Errors come back as integers.** A live value of `#DIV/0!` is the Int32 SCODE
|
|
70
|
+
`-2146826281`; `#VALUE!` is `-2146826273`, `#REF!` `-2146826265`, `#NAME?`
|
|
71
|
+
`-2146826259`, `#NUM!` `-2146826252`, `#N/A` `-2146826246`. In WPS,
|
|
72
|
+
`WorksheetFunction.IsError` returns `False` for them and `SpecialCells(16)` throws, so
|
|
73
|
+
the practical test is "is this value an Int32?" — then read `Range.Text`,
|
|
74
|
+
`Range.Formula` and `Range.Address(0,0)` for that cell alone.
|
|
75
|
+
- `Range.Text` is a per-cell property. On a multi-cell range WPS returns `DBNull`, so the
|
|
76
|
+
tool reads it cell by cell (that is why `--display` is capped).
|
|
77
|
+
- **Assigning one formula to a range fills it with relative adjustment.** Setting
|
|
78
|
+
`A1:A3` to `=B1` gives `=B1`, `=B2`, `=B3`. This is the cheap way to fill a column; it
|
|
79
|
+
is also the way to accidentally create a formula you did not intend when the target is
|
|
80
|
+
more than one cell.
|
|
81
|
+
- Dates are serials (`days since 1899-12-30`, the 1900 date system). `DateSerial(y,m,d)`
|
|
82
|
+
gives the number; a `NumberFormat` gives the look.
|
|
83
|
+
- Formulas are text. There is no calculation on write; the value updates when the
|
|
84
|
+
application recalculates, which is why `recalc` exists.
|
|
85
|
+
|
|
86
|
+
## Number formats
|
|
87
|
+
|
|
88
|
+
`Range.NumberFormat` takes format *codes*, not locales: `#,##0`, `#,##0.00`, `0.0%`,
|
|
89
|
+
`"$"#,##0.00`, `mmm-yy`, `d-mmm`, `@`. Use invariant ASCII codes — the dot is always the
|
|
90
|
+
decimal point inside the code, whatever the machine's `Application.DecimalSeparator`
|
|
91
|
+
says. WPS returns empty strings for `DecimalSeparator`/`ThousandsSeparator`, so do not
|
|
92
|
+
read locale from the app and do not build codes from locale data.
|
|
93
|
+
|
|
94
|
+
- Format is display only. The stored value keeps full precision; never round data to make
|
|
95
|
+
it read right.
|
|
96
|
+
- One format per column. Mixing `#,##0` and `#,##0.00` down a single column is the most
|
|
97
|
+
common visual defect in a live sheet.
|
|
98
|
+
- Percentages carry precision: one decimal for analytical tables, zero for dashboards,
|
|
99
|
+
two when the differences are small. The code encodes that: `0.0%`, `0%`, `0.00%`.
|
|
100
|
+
- `###` in the window means the column is too narrow for the formatted value, not that
|
|
101
|
+
the value is wrong. Widen with `ColumnWidth` (points-ish, default about 8.43) or
|
|
102
|
+
`EntireColumn.AutoFit()`, and check the result with `--display`.
|
|
103
|
+
|
|
104
|
+
## Colour is BGR
|
|
105
|
+
|
|
106
|
+
`Interior.Color` and `Font.Color` are OLE colour longs written `0xBBGGRR`, while every
|
|
107
|
+
spec in this repo is `#RRGGBB`. Convert explicitly:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
ole = red + green * 256 + blue * 65536 # #RRGGBB -> BGR long
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`#C00000` becomes `192`; a pure blue fill becomes `16711680`. Setting `ColorIndex = -4142`
|
|
114
|
+
removes a fill (`Interior.Color` then reads back `16777215`). Theme colours and tints are
|
|
115
|
+
not addressable this way: if the workbook's palette matters, use the workbook's own
|
|
116
|
+
existing colours rather than inventing one.
|
|
117
|
+
|
|
118
|
+
## Font, borders, alignment, layout
|
|
119
|
+
|
|
120
|
+
- `Range.Font`: `Name`, `Size`, `Bold`, `Italic`, `Color`, `Underline`, `Strikethrough`.
|
|
121
|
+
One family across the sheet; the repo default is Helvetica Neue → Helvetica → Arial →
|
|
122
|
+
Aptos, whichever the workbook already uses.
|
|
123
|
+
- `Range.Borders.Item(index)`: 7 left, 8 top, 9 bottom, 10 right; `LineStyle` (1 continuous),
|
|
124
|
+
`Weight` (2 thin), `Color`. `BorderAround(1, 2)` draws a thin outline in one call.
|
|
125
|
+
- `HorizontalAlignment` / `VerticalAlignment` take `xlHAlign*` constants (`-4131` left,
|
|
126
|
+
`-4108` center, `-4152` right) and `xlVAlign*` (`-4160` top, `-4108` center, `-4104`
|
|
127
|
+
bottom). The tool maps the readable names for you.
|
|
128
|
+
- `Range.Merge()`, `Range.UnMerge()`, `Range.WrapText`, `Range.IndentLevel`,
|
|
129
|
+
`EntireColumn.ColumnWidth`, `Tab.Color`, `Rows.Hidden`.
|
|
130
|
+
- `FreezePanes` lives on `Window`, not on the sheet, and did not stick on a hidden
|
|
131
|
+
instance in WPS. The tool deliberately has no freeze-pane verb; if the user needs panes
|
|
132
|
+
frozen, tell them to do it, or do it visibly in a shown window.
|
|
133
|
+
- Whole-sheet `AutoFit` and `Select`/`Activate` are traps: they change the user's view,
|
|
134
|
+
can take seconds on a large sheet, and `ScreenUpdating` does not hide the flicker from a
|
|
135
|
+
user who is looking at the window.
|
|
136
|
+
|
|
137
|
+
## Objects beside the cells
|
|
138
|
+
|
|
139
|
+
- **Tables**: `$sheet.ListObjects.Add(1, $range, [Type]::Missing, $has_headers)` creates
|
|
140
|
+
a `ListObject`. PowerShell cannot reproduce VBA's empty argument positions — pass
|
|
141
|
+
`[Type]::Missing` for the `Destination` slot. Created tables get localized default
|
|
142
|
+
names (`表1`), so name them. With `has_headers = 0` the application *generates a header
|
|
143
|
+
row above the data*, which shifts the values down one row and makes the table one row
|
|
144
|
+
taller than the range you named. Extend an existing table with `ListObject.Resize`
|
|
145
|
+
rather than adding a second one over the same cells.
|
|
146
|
+
- **Charts**: `$sheet.ChartObjects().Add(left, top, width, height)` → `.Chart` →
|
|
147
|
+
`.SetSourceData($range)` + `.ChartType`. `HasTitle`/`ChartTitle.Text` set the title.
|
|
148
|
+
`ChartType` numbers: column 51, stacked column 52, bar 57, stacked bar 58, line 4, line
|
|
149
|
+
with markers 65, area 1, stacked area 76, pie 5, doughnut -4120, scatter -4169,
|
|
150
|
+
scatter with lines 74. A chart over an empty range renders blank — check the source
|
|
151
|
+
cells before blaming the chart.
|
|
152
|
+
- **Shapes**: `$sheet.Shapes.AddShape(...)`, `AddTextbox`, `AddPicture`. They float over
|
|
153
|
+
cells and are not part of the used range; anchor them to a cell (`TopLeftCell`) so they
|
|
154
|
+
move with the data.
|
|
155
|
+
- **Pivots**: `PivotTables`, `PivotFields`. Read and report them; never rebuild one
|
|
156
|
+
through COM unless the user asked for a new pivot — the field layout is not recoverable
|
|
157
|
+
from a failed attempt.
|
|
158
|
+
- **Names**: `$workbook.Names`, `Range.Name`. Names break when you delete the cells they
|
|
159
|
+
point at (`#REF!` in the name), so a rename or a row delete is a contract change.
|
|
160
|
+
- **Conditional formats**: `Range.FormatConditions`. Appending a condition to a range
|
|
161
|
+
that already has one edits the *existing* set; a "fix" here can silently change rules
|
|
162
|
+
the user depends on. Read first, and keep the range bounded.
|
|
163
|
+
- **Validation**: `Range.Validation` — same rule. Read the existing rule before writing a
|
|
164
|
+
new one.
|
|
165
|
+
|
|
166
|
+
## Calculation and freshness
|
|
167
|
+
|
|
168
|
+
- `Application.Calculation`: `-4105` automatic, `-4135` manual. A workbook left in manual
|
|
169
|
+
mode shows stale numbers after your edit; `recalc` runs `CalculateFull` across every
|
|
170
|
+
open workbook and reports the mode it found.
|
|
171
|
+
- `CalculateFull` recalculates dependencies, not just the active sheet. `CalculateFullRebuild`
|
|
172
|
+
rebuilds the dependency tree — use it only when a value looks impossible, because it is
|
|
173
|
+
slow on a large model.
|
|
174
|
+
- Iterative calculation (`Application.Iteration`) is off by default. Circular references
|
|
175
|
+
that "worked" for the user are a sign it was on; do not turn it on to make an edit
|
|
176
|
+
succeed.
|
|
177
|
+
|
|
178
|
+
## Latency, failures, retries
|
|
179
|
+
|
|
180
|
+
- Every property access is an RPC. A trivial call (`info`, three reads) took about 1.2–1.5 s
|
|
181
|
+
on this host; a call that formats 100 cells one at a time can take tens of seconds.
|
|
182
|
+
**Batch**: one `write_range` for a block, one `style_range` for a range, one `set_formula`
|
|
183
|
+
for a column. Do not loop calls per cell.
|
|
184
|
+
- The default timeout in the tool is 180 s. Raising it is legitimate for a big paste;
|
|
185
|
+
lowering it below a second will fail on a busy application.
|
|
186
|
+
- Failures you will meet:
|
|
187
|
+
- `0x800401E3` — nothing is running. Remediate by asking the user to open the workbook.
|
|
188
|
+
- `0x8001010A` (RPC_E_SERVERCALL_RETRYLATER) — the application is busy (a modal dialog,
|
|
189
|
+
a recalculation, a user dragging a window). Read again, and if it persists tell the
|
|
190
|
+
user there is a dialog blocking the app.
|
|
191
|
+
- "Object required" / a stale proxy — usually after the user closed the workbook you
|
|
192
|
+
were holding. Re-attach by name; never reuse the old object.
|
|
193
|
+
- A method that exists in Excel raising "does not contain a method named …" in WPS — the
|
|
194
|
+
WPS object model is a subset. Fall back to a simpler route (formatting via
|
|
195
|
+
`Value2`/`NumberFormat` instead of a specialised helper).
|
|
196
|
+
- **Nothing is transactional.** A call that fails halfway leaves the cells it already
|
|
197
|
+
wrote. The retry protocol is: `read_range` the block, compare with intent, write only
|
|
198
|
+
what is missing or wrong. Replaying the same batch is how a live document gets
|
|
199
|
+
duplicated rows.
|
|
200
|
+
|
|
201
|
+
## The one rule that outranks the rest
|
|
202
|
+
|
|
203
|
+
A live edit mutates a document the user is looking at and may have unsaved changes in.
|
|
204
|
+
**Read and diff before writing.** `read_range` the target with `--formulas`; note whether
|
|
205
|
+
`info` says the workbook is `saved: false`; then make the smallest write that satisfies the
|
|
206
|
+
request. If the diff shows values you did not expect, stop and ask — the user's unsaved
|
|
207
|
+
work is more important than finishing the task.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Answering questions about a workbook the user has open
|
|
2
|
+
|
|
3
|
+
Read-only work: no writes, no saves, no restyling. The deliverable is an answer with cell
|
|
4
|
+
references the user can check, not a changed document.
|
|
5
|
+
|
|
6
|
+
## Reading
|
|
7
|
+
|
|
8
|
+
- `info` first: which workbook, which sheets, which used ranges, tables, charts, pivots.
|
|
9
|
+
That tells you where to look and whether the thing the user is asking about even exists.
|
|
10
|
+
- `read_range --formulas` for the cells that matter. You almost always need both: the
|
|
11
|
+
value tells you *what*, the formula tells you *why*. A number with no formula behind it
|
|
12
|
+
is an input the user typed; a formula with no precedent is a number you cannot trust.
|
|
13
|
+
- `read_range --display` when the question is about how something *reads* (`###`, a
|
|
14
|
+
truncated label, a date that shows as a serial). Displayed text follows the number
|
|
15
|
+
format; the value does not.
|
|
16
|
+
- Read the workbook's own labels — row and column headers, period names, "Actual" vs
|
|
17
|
+
"Forecast" markers, units — before interpreting a cell. `D14` is only meaningful when
|
|
18
|
+
you know it is "Q3 advertising spend, USD".
|
|
19
|
+
- The window may be ahead of the disk file. If `info` shows `saved: false`, the numbers
|
|
20
|
+
you read are the user's unsaved state; say so if the answer would differ from the file.
|
|
21
|
+
|
|
22
|
+
## Answering
|
|
23
|
+
|
|
24
|
+
1. **Locate the output by its labels**, not by guesswork: find the row/column that names
|
|
25
|
+
the metric and the period the user asked about, then read the intersection.
|
|
26
|
+
2. **Trace the precedent chain** back from the output to labelled assumptions or raw
|
|
27
|
+
inputs. `read_range --formulas` on each step; stop at cells whose value is typed rather
|
|
28
|
+
than computed. Reporting an intermediate total as the cause is the classic error.
|
|
29
|
+
3. **Reconcile before asserting.** If a total does not equal the sum of its parts, that is
|
|
30
|
+
the finding — report the gap and the cells, do not average it away.
|
|
31
|
+
4. **Compute from the underlying values.** A cell showing `1.2` may hold `1.2345`; the
|
|
32
|
+
answer to "what is the margin" uses the stored value, and if the requested precision
|
|
33
|
+
needs the rounded number, say that you are using the displayed value.
|
|
34
|
+
5. **Rank drivers** by absolute contribution when the question is "why did it move".
|
|
35
|
+
Report the top two or three with their cells and amounts, not a list of everything.
|
|
36
|
+
6. **Cite cells** in the reply: `` `Summary!D14` shows 1,234 units because `Build!F7:F12`
|
|
37
|
+
sums to that ``. A claim without an address is not verifiable.
|
|
38
|
+
7. If two sheets disagree, say which one you believe and why (more recent period, source
|
|
39
|
+
data rather than a copy, a formula chain rather than a paste), and do not "fix" either
|
|
40
|
+
without being asked.
|
|
41
|
+
|
|
42
|
+
## Sensitive reviews
|
|
43
|
+
|
|
44
|
+
Clinical records, payroll and individual compensation, customer-level data: answer at the
|
|
45
|
+
level the user asked for and no lower. Inspect structure, formats, dependency chains and
|
|
46
|
+
formulas as evidence, and do not echo restricted values into the chat unless the user
|
|
47
|
+
needs that exact figure to act. If the question cannot be answered without exposing
|
|
48
|
+
personal data, say what you can answer instead.
|
|
49
|
+
|
|
50
|
+
## Limits
|
|
51
|
+
|
|
52
|
+
- Do not equate the live window with the saved file, and do not present a read-only
|
|
53
|
+
question as if you had verified the disk copy.
|
|
54
|
+
- If a formula depends on external links, volatile functions (`NOW()`, `RAND()`) or a
|
|
55
|
+
pivot cache that has not been refreshed, say the number is provisional.
|
|
56
|
+
- If the workbook is protect-structured or the sheet is protected, reads still work;
|
|
57
|
+
report the protection rather than working around it.
|
|
58
|
+
- `#REF!`, `#DIV/0!` and friends in the cells are part of the answer, not noise: name the
|
|
59
|
+
cell, the formula and what it broke.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Style guidelines for a live sheet
|
|
2
|
+
|
|
3
|
+
Style is subordinate to content and to the user's own file. Precedence, strongest first:
|
|
4
|
+
|
|
5
|
+
1. What the user asked for, in this conversation.
|
|
6
|
+
2. The workbook's existing conventions — fonts, colours, borders, tab colours, number
|
|
7
|
+
formats. Match them; do not impose a house style on someone else's document.
|
|
8
|
+
3. The domain guidance for the kind of model (`domain_guidance/`).
|
|
9
|
+
4. The defaults below.
|
|
10
|
+
|
|
11
|
+
Look before you paint: `info` for tab colours and structure, `read_range` for the formats
|
|
12
|
+
a neighbouring block already uses. Restyling a user's sheet because your defaults are
|
|
13
|
+
tidier is a defect, not a service.
|
|
14
|
+
|
|
15
|
+
## Defaults that are safe anywhere
|
|
16
|
+
|
|
17
|
+
- **Font family**: one per workbook. If it has none, Helvetica Neue → Helvetica → Arial →
|
|
18
|
+
Aptos. **Two sizes**: 10 pt body, 14 pt title, 16 pt ceiling. Never introduce a third
|
|
19
|
+
family or a decorative size.
|
|
20
|
+
- **Alignment**: text left, numbers right, headers centred horizontally and middle
|
|
21
|
+
vertically. Do not centre numbers to look neat; they lose their decimal alignment.
|
|
22
|
+
- **Headers**: bold, one rule under the last header row (`border: "outline"` on the header
|
|
23
|
+
block, or a bottom border on the row). No merged cells in working headers — merge only a
|
|
24
|
+
single spanning title, and prefer Center Across Selection for that.
|
|
25
|
+
- **Inputs vs calculations**: an input cell the user is expected to type into gets a light
|
|
26
|
+
fill (`#FFF2CC` amber) and a thin border; calculated cells keep a plain fill. If the
|
|
27
|
+
whole block is inputs, one header note beats painting every cell.
|
|
28
|
+
- **Gridlines**: a clean output or dashboard sheet hides them (`ActiveWindow.DisplayGridlines
|
|
29
|
+
= $false`, a view setting, not a cell format) and uses thin structural borders instead.
|
|
30
|
+
A working sheet keeps them.
|
|
31
|
+
- **Borders**: outline a block, hairline between header and body. No box around every cell,
|
|
32
|
+
no double lines, no thick decorative frames.
|
|
33
|
+
- **Column widths**: set them once per block (`column_width` in `style_range`), not per
|
|
34
|
+
cell. Widen for the formatted value, then check with `read_range --display` for `###`.
|
|
35
|
+
- **Conditional formatting**: bounded to the data range, one or two rules. Never a whole
|
|
36
|
+
column, never a rule that paints a user input cell.
|
|
37
|
+
- **Freeze panes** are not a styling nicety; the tool cannot set them on a hidden window.
|
|
38
|
+
If scrolling is the complaint, say so and let the user freeze the row.
|
|
39
|
+
|
|
40
|
+
## Model layouts
|
|
41
|
+
|
|
42
|
+
- Summary above detail, outputs before workings, assumptions grouped in one block rather
|
|
43
|
+
than scattered. A reader should be able to look at the top-left and understand the sheet.
|
|
44
|
+
- One blank row at the top of a new output sheet, the title in an unfilled cell on the
|
|
45
|
+
left, a thin rule under it. No logo, no merged banner, no slogan.
|
|
46
|
+
- Rows of commentary go to the right of the numbers, separated by one blank column; they
|
|
47
|
+
never sit between a label and its value.
|
|
48
|
+
- Helper rows: italic, grouped under the block they serve, collapsed if the workbook
|
|
49
|
+
already uses grouping. Helper columns live outside the printed range or on a separate
|
|
50
|
+
helper sheet.
|
|
51
|
+
- A case or scenario selector is a visible label plus a validated cell: `Case Selected:`
|
|
52
|
+
and the value on display. Do not hide the control in a defined name.
|
|
53
|
+
- Section bands (a filled row spanning the table) get one outline around the whole
|
|
54
|
+
section, not per row.
|
|
55
|
+
- Dark header fill with white text, or plain text with a rule. Pick one per workbook.
|
|
56
|
+
|
|
57
|
+
## Finance conventions
|
|
58
|
+
|
|
59
|
+
These are long-standing reader expectations in financial models; a reviewer notices when
|
|
60
|
+
they are violated.
|
|
61
|
+
|
|
62
|
+
- **Colour encodes provenance.** Blue font for editable hard-coded inputs, black for
|
|
63
|
+
formulas on the same sheet, green for links to another sheet, red for links to an
|
|
64
|
+
external workbook. Results on an output view stay black or the brand dark colour.
|
|
65
|
+
- **Number formats**: `#,##0` for amounts, `#,##0.00` for per-share and price data,
|
|
66
|
+
`0.0%` for rates, `( )` for negatives and `-` for zero in accounting views
|
|
67
|
+
(`#,##0;(#,##0);"-"`). Currency symbol on the first monetary row and on totals, not on
|
|
68
|
+
every row.
|
|
69
|
+
- **Indent formats** (` @` for text labels, `_(`-style spacing) map a hierarchy without
|
|
70
|
+
empty columns.
|
|
71
|
+
- **Totals** sit flush left in the label column, bold, with the rule above them. A total
|
|
72
|
+
that is a hard number rather than a formula is a finding, not a style choice.
|
|
73
|
+
- **Period labels** follow `mmm-yy`, `d-mmm`, `yyyy`, `Q#:YY`, `FY:YY` as the workbook
|
|
74
|
+
already does. A date column has one format down its whole length.
|
|
75
|
+
- **Actuals vs forecast**: the change of basis is visible — a divide, a different fill, or
|
|
76
|
+
a label — and never inferred from a colour alone.
|
|
77
|
+
- A model that needs a gutter between the row labels and the numbers gets columns A:B
|
|
78
|
+
reserved for it. Do not retrofit a gutter onto a sheet that does not have one.
|
|
79
|
+
|
|
80
|
+
## Warning colour, used sparingly
|
|
81
|
+
|
|
82
|
+
- Input that must be refreshed: amber fill (`#FFF2CC`), normal font.
|
|
83
|
+
- Critical error or failed check: light red fill (`#FFC7CE`) plus bold red text
|
|
84
|
+
(`#9C0006`).
|
|
85
|
+
- Passing checks: neutral. A green wash over every PASS makes the one red row invisible.
|
|
86
|
+
- Never encode a value only in colour — a reader with a monochrome printout, or a colour
|
|
87
|
+
vision deficiency, must still see the meaning. Put the flag in a cell.
|