Commit Graph
16 Commits
Author SHA1 Message Date
DongHyeonka 11c2713139 feat: let Studio create the topics and projects publishing requires
Publishing needs a topic and nothing could create one. The backend now owns
that surface; this is its consumer — the management contract vendored, a
gateway over its nine operations, and one Studio screen that lists, creates,
and deletes topics and projects.

The screen adds no CSS. It reuses the classes the working-copy list already
uses, so it inherits Studio's spacing, type, and colour rather than growing a
second visual vocabulary beside them. Scope stops at list/create/delete:
renaming, phase changes, and visibility are implemented in the backend and
declared in the contract, but their screens are a separate design.

Two real defects surfaced while making the public port async, and both would
have shipped:

The search page and the header search dialog shared a query key. With an empty
query, `["tech-log","search",""]` was identical for both, so react-query
handed one surface the other's cache — different shapes — and the page died
reading a field that was not there. Keys now name the surface.

The explore filter's selects are uncontrolled and read `defaultValue`, which
React applies once. Their options arrive later now, so the first render had
nothing to match and the value stayed empty: a topic in the URL no longer
showed as selected. The form key includes whether the catalog has arrived, so
it remounts with the options present. Controlled inputs would be the other
answer, but this form submits to build a URL — the URL owns the value.

The route brought its own bookkeeping: a build chunk, a manual accessibility
evidence file, and the CI artifact baseline that counts them. The gate pins a
digest of its own shape precisely so a new route cannot slip in without that
count being reviewed.

Test harnesses that render public screens now assemble the query providers and
await the settled paint, because the screens they render became async.
2026-08-20 23:40:15 +09:00
DongHyeonka c362ec6100 feat: vendor the public read contract, and give it its own source switch
The public surface — 17 of the 28 registered routes — reads from a 29KB
TypeScript fixture and never touches the backend. `TECH_LOG_STUDIO_SOURCE`
only ever switched the Studio gateways; `publicContent` was wired to the
static adapter unconditionally, so no configuration could make the public
site show published content. This is the first half of closing that: the
contract and the switch, with the adapter still to come.

The generator now vendors both canonical contracts instead of one. They are
independent — different services on different schedules — so each carries
its own digest and operation list, and updating one leaves the other's drift
gate quiet.

`TECH_LOG_PUBLIC_SOURCE` is deliberately a second flag rather than a rename
of the Studio one. The combination that matters right now is exactly the one
a single flag cannot express: the authoring backend is live while the public
read API does not exist yet. production stays on MOCK for that reason —
pointing it at HTTP today would empty the live site — and moves when the
backend serves /api/v1/public.

Also records the compatibility evidence the registry gate wanted for the
Studio access change in fff5e6f. That gate has been failing since, which is
on me: the change was real and breaking, and it shipped without the note
explaining that route ids and schemas are untouched and only the access
classification moves.
2026-08-20 16:19:53 +09:00
DongHyeonka 83409bef7a feat: give the frontend a deployment artifact, and show its logo
The repository had no container image and no production-shaped serving
configuration. `dist/server.mjs` is a preview server that applies neither
the security headers nor the cache policy `config/hosting/` declares, so a
deployment had nothing correct to run.

`scripts/generate-nginx-config.ts` derives the server block from
`dist/tech-log-serving-contract.json` plus the two hosting policy files, so
the served headers and cache lifetimes cannot drift from what the contract
declares. It emits no TLS and no proxy blocks: the edge terminates TLS and
routes /api, and baking a backend address into the image would tie the
bundle to one deployment. Static surfaces use `alias` because a base-path
build serves /dev/assets/... out of dist/assets/..., which `root` plus URI
would look for one directory too deep.

The image copies that config next to the bundle and normalises permissions:
the build writes config.json 0600, which nginx cannot read, so the container
came up healthy and answered 403 for the one file the SPA needs to boot.

index.html never referenced public/favicon.svg. The file shipped and nginx
served it, but browsers asked for /favicon.ico, got a 404, and fell back to
the default icon. `%BASE_URL%` rather than an absolute path so a prefixed
deployment points at its own copy.

development.json moves to the HTTP Studio source; the mock source has no
backend to authenticate against, which is the whole point of that profile.
2026-08-20 16:14:09 +09:00
DongHyeonkaandClaude Opus 5 4090c8681d test: gate the dev release manifest against the compiled contract set
Nothing in the gate set read `public/*.json`. Every static gate passed and the
whole suite passed while `pnpm dev` rendered the boot-error screen instead of
the app, which is the only reason the drift survived two contract changes.

`check:dev-release-manifest` compares the fixture's `setAlgorithm`, `setDigest`
and package set against what `generate-contract-set.ts` composes, and is
registered on FE-GATE-010 next to `check-tech-log-contract` so CI executes it.
Unlike the refresh wired into contract generation, this observes the composed
set directly, so it also catches a contribution added to or removed from
`installed-contract-contributions.ts`.

`CANONICAL_GATE_SHAPE_SHA256` recomputed by hand, as always: the committed
constant 98d19911... was first reproduced from the committed `gates.json` with
an independent transcription of `canonicalGateShapeSha256`, and only then was
b4096244... hashed from the new one. Command counts move 84/96 -> 85/97;
artifacts stay at 130 because the gate publishes no evidence file, matching
`check-tech-log-contract`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 14:07:40 +09:00
DongHyeonkaandClaude Opus 5 419d9d006d ci: give test:tech-log its own gate command and junit evidence
The TechLog suite already ran in CI, but only inside `test:coverage`'s combined
`vitest run tests/runtime-schema tests/unit … tests/features/tech-log`
invocation on FE-GATE-005. A TechLog regression therefore surfaced as a
coverage-gate failure, and the only junit that carried it was coverage.xml,
which reports every other suite at the same time.

`test-tech-log` now sits on FE-GATE-007 beside `test-reference-feature`, the
sibling it mirrors — both drive a suite under `tests/features/` — and declares
`artifacts/tests/tech-log.xml`, which `test:tech-log` already wrote, as its own
command-generated junit evidence. The gate log now names
`$ corepack pnpm test:tech-log` as its own step and the failure lands on the
suite that produced it.

Adding a command and an artifact moves the exact-count authority to 84
definitions / 96 references / 130 artifacts (109 evidence references), and
changes the canonical gate shape digest because FE-GATE-007's commandIds and
evidenceArtifactIds are part of it. There is no tooling to regenerate that
digest, so it was recomputed by hand under the standing procedure: a fresh
transcription of `canonicalGateShapeSha256` first reproduced the committed
f3cc9075… from the unedited config/ci/gates.json — proving the transcription,
not just agreeing with whatever the check compares against — and only then
hashed the edited file to 98d19911….

`corepack pnpm ci:gate -- FE-GATE-007` passes end to end; the generated
workflow bytes are unchanged, since the yml dispatches gates rather than
commands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 12:58:41 +09:00
DongHyeonkaandClaude Opus 5 f19be639a3 ci: run the TechLog contract drift gate in CI and test:all
`check:tech-log-contract` existed and worked but nothing ran it. No gate in
`config/ci/gates.json` referenced it and `test:all` did not chain it, so a
hand-edit of the vendored canonical yaml or of `generated.ts` passed every
gate the repository actually executes -- the exact regression the digest pin
exists to prevent.

FE-GATE-010 (architecture/contract governance) now owns the command, beside
`check-registries` and `check-ci`, and `test:all` runs it in front of
`test:tech-log`. The canonical authority baseline moves to 83 command
definitions / 95 references and the gate-shape SHA-256 is recomputed with
`canonicalGateShapeSha256`; the recomputation was first verified by
reproducing the previous constant from the previous gates.json.

`tests/features/tech-log/contract-generation.test.ts` now fails if either
wiring is removed again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 09:03:14 +09:00
DongHyeonkaandClaude Opus 5 b11aa94f1c feat: add the TechLog Studio asset library route and screen
Adds TECH_LOG_STUDIO_ASSETS (/studio/assets) as a route reachable but
excluded from primary Studio navigation (navigationLabel/navigationOrder
null), plus the AssetLibrary screen that lists assets, shows usage, and
lets an operator archive or hard-delete one. canHardDelete() is a pure
gate mirroring the server's ASSET_IN_USE rule so the screen never offers
an action the server would refuse.

Adding a 28th route also required updating the route-scoped CI
accessibility-evidence gate (FE-GATE-009 in config/ci/gates.json, plus
its authority-baseline counts and shape digest in
scripts/contracts/ci-gates.ts) and the Vite route-to-chunk map that
scripts/generate-build-manifest.ts depends on, or test:unit and the
production build both fail. See task-11-report.md for the full
breakdown.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 07:26:05 +09:00
DongHyeonka 3b641906b8 feat: select the TechLog Studio adapter from runtime configuration
Adds TECH_LOG_STUDIO_SOURCE (MOCK | HTTP, default MOCK) to the V2 runtime
config schema so a build can switch createTechLogFeatureInstalledInput
between the mock and HTTP Studio gateways without a rebuild. V1 documents
predate the key and always normalize to MOCK. The HTTP gateway is
constructed with only { operations } per Task 4's actual signature -
no CSRF provider is wired here; that lands with attachCredentials at a
later composition-root task.

Updates every existing Studio test call site to the new required
createTechLogFeatureInstalledInput(context) signature via a shared
tests/helpers/studio-install-context.ts MOCK fixture, so the whole
existing Studio suite keeps exercising the mock adapter unchanged.
2026-08-18 01:57:15 +09:00
DongHyeonkaandClaude Opus 5 7d1ccccbcd Merge branch 'main' into feature/techlog-ui-migration
Integrates the frontend template sync (a0fbafb → 5434760) into the TechLog UI
migration. Merged in this direction so every conflict is resolved and proved in
the worktree; main is only fast-forwarded afterwards and never holds a state
that was not verified here.

15 conflicts. The rule throughout: keep the template's mechanism, keep the
product's content, and never invent a third state neither branch would accept.

The template's product manifest and its runtime feature kill switch are adopted.
The route registry is deliberately not composed from contract.routes: the
reference feature still declares screens this product deleted, and reducing over
them would register paths with no component behind them. ROUTE_FEATURE_OWNER is
narrowed to registered routes for the same reason. The first resolution did
compose from contract.routes and was rejected by product-features.test.ts.

Three files pinned counts and a digest describing the gate contract. Neither
side's numbers describe the merged config/ci/gates.json, so they were recomputed
from it rather than chosen: 27 gates, 82 commands, 94 command references, 107
evidence references, 128 artifacts, shape sha256 5063586d.

README.md and docs/accessibility/manual-checklist.md now enumerate this
product's 27 routes, which the template's own verify:documentation requires.

product-feature-switch.test.tsx was rewritten around the invariant that still
applies here — no registered route without a component — rather than deleted
with the screens it used to exercise.

docs/operations/template-merge-2026-08-17.md records every decision, the gate
results, and the three follow-ups this merge deliberately did not decide.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 18:38:08 +09:00
DongHyeonka 3a7c5deca0 fix: complete TechLog migration evidence 2026-08-16 04:55:52 +09:00
DongHyeonka 6c2780b7a7 test: prove TechLog UI migration parity 2026-08-16 02:48:26 +09:00
DongHyeonka c5c8b9423c feat: complete TechLog Studio publication flow 2026-08-16 00:35:11 +09:00
DongHyeonkaandClaude Opus 5 bdee07a93b chore: sync the frontend template from a0fbafb to 5434760
Carries eight template commits: the provider sandbox actually running, release
admission to a named environment, the product feature manifest with its runtime
kill switch, architecture and documentation rules that match what is enforced,
the removability fixtures, and the browser, visual and performance evidence.

Product identity is unchanged. `package.json` keeps `tech-log-frontend` and the
catalog keeps the Tech Log naming; the home page was not in the delta. The
visual baselines are this product's own — the template's were excluded from the
transplant and these were regenerated here, where the only difference is the
platform overview's new product-feature section.

What this repository gains operationally: `config/runtime/{local,development,
staging,production}.json` with `FE-GATE-027` refusing an artifact whose runtime
document does not match the environment it is being admitted to, and
`FEATURE_OVERRIDES` for taking an installed feature out of service without a
rebuild.

Verified here: eight gates green, build green, visual 5/5, and 1,858 of 1,859
tests in the suites that do not need a sandbox — the one failure passes in
isolation and is a jsdom lazy-chunk timeout under parallel load. The provider
suites cannot run on this machine at all: `kernel.apparmor_restrict_unprivileged
_userns=1` makes `bwrap --unshare-net` fail, reproducible without any code from
either repository.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 21:34:19 +09:00
DongHyeonka adb8613cb9 feat: add grouped TechLog route contracts 2026-08-15 20:30:32 +09:00
DongHyeonkaandClaude Opus 5 4bff9ca151 chore: sync the frontend template from 4dc033c to 8157ad4
The product was materialized from the template at `4dc033c` and has stayed
on it through 43 template commits, so it was missing all three rounds of
adapter remediation — including files it never had, such as the shared
`abortable-operation` primitive and the `exact-snapshot` decoder that
later fixes are written against. Taking only the newest round was not
possible for that reason: the delta is coherent only as a whole.

The product had not touched `src/adapters` at all since materialization,
so the 140-file delta applied with a three-way merge and no conflicts.
`package.json` was the single overlap and merged cleanly: the product owns
`name`, the template contributed `check:adapter-inventory`,
`check:remediation-ledger` and the image-resolve-signal type fixture.
All 24 product-owned files — README, index.html, CI workflow, i18n
catalog, home page, generated schemas, evidence scripts, component and
visual snapshots — are byte-identical to `main`.

`template.lock.json` now pins the synced revision and tree.

Verified in this repository, not inherited from the template: six type
projects, lint, nine gates (adapter inventory, remediation ledger,
registries, diagnostics, realtime boundaries, architecture, browser
file/storage boundaries, optional recipes, documentation), the production
build, and 2,054 of 2,073 tests. The 19 failures are all in
`tests/unit/ci-artifact-contract.test.ts` and are the same pre-existing
sandbox RLIMIT, EMFILE, umask and `/tmp` permission behaviour the template
records; four suites that failed once under parallel load pass in
isolation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 12:04:58 +09:00
DongHyeonka 40107eec84 chore: initialize from frontend template 4dc033c 2026-08-13 18:23:26 +09:00